Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Discovering the Future of Java

4.00/5 (1 vote)
8 Dec 2017CPOL6 min read 14.6K  
Discovering the future of Java

Java 6 was released in 2006 and Java 7 in 2011. No major changes were added to Java 7, many of the new features were present in Java 6 updates. After Java 7, Oracle decided to implement a two years roadmap planning for Java, and the next major release will be available in 2013.

Java 8 has some interesting new features like lambda expressions, but the major new feature planned was Jigsaw, in fact Jigsaw was originally intended for Java 7 but was deferred to Java 8 and now it’s moved to Java 9.

Here’s a brief description from Jigsaw website of the motivations behind it:

“The original goal of Jigsaw was to design and implement a module system focused narrowly upon the goal of modularizing the JDK, and to apply that system to the JDK itself. We expected the resulting module system to be useful to developers for their own code, and it would have been fully supported for that purpose, but it was not at the outset intended to be an official part of the Java SE Platform Specification.”

When discovering the goal of Jigsaw, the first question we can ask is:

Why Invent Another Module System? The OSGi Approach is Not Sufficient?

OSGi as described in a previous post is a mature approach used by Eclipse and it’s used by many other projects. But what’s interesting with Jigsaw is it will be integrated into the Java platform, and the JRE itself as you will discover later is structured with Jigsaw modules, and maybe with Java 9, the modular approach will be mostly adopted than now.

To discover this new feature, we will analyze the custom edition of Java 8 implementing Jigsaw. For this purpose, JArchitect will be used to go inside the design and implementation of Jigsaw.

The standard Java 8 is structured with jars like all previous Java versions, but with Jigsaw, the structure is changed. Here’s the dependency graph between packages for standard java8.

Image 1

The JRE is structured by using jars, and each jar contains many types, and almost all types are present in the rt.jar, this structure is not clean, and some dependency cycles exist between jars, however the JRE implementing Jigsaw is structured by using modules, and each major features are isolated to a specific module, the structure became cleaner.

Image 2

Module

A module is a collection of Java types with a name, an optional version number, and a formal description of its relationships to other modules. In addition to Java types, a module can include resource files, configuration files, native libraries, and native commands. A module can be cryptographically signed so that its authenticity can be validated.

The Java programming language is extended to include module declarations for the purpose of defining modules, their content, and their relationships to other modules. A compilation unit containing a module declaration is, by convention, stored in a file named module-info.java and compiled into a file named module-info.class.

And to better understand the module concept, let’s go inside the jndi module, and here’s its declaration:

Java
module jdk.jndi @ 8-ea {
    requires local jdk.auth.internal@8-ea;
    requires local jdk.base.internal@8-ea;
    requires optional jdk.desktop@8-ea;
    requires jdk.rmi@8-ea;
    requires jdk.tls.internal@8-ea;
    requires optional service javax.naming.ldap.StartTlsResponse;
    provides service sun.net.spi.nameservice.NameServiceDescriptor 
                with sun.net.spi.nameservice.dns.DNSNameServiceDescriptor;
    // default view exports
    exports com.sun.security.auth.*;
    exports com.sun.security.auth.module.*;
    exports javax.naming.*;
    exports javax.naming.directory.*;
    exports javax.naming.event.*;
    exports javax.naming.ldap.*;
    exports javax.naming.spi.*;

    view jdk.jndi.internal {
        exports com.sun.jndi.toolkit.url.*;
        exports sun.net.dns.*;

        permits jdk.cosnaming;
        permits jdk.kerberos;
    }
}

Let’s discover each module section.

requires

Jndi depends upon other modules, until now nothing new, the jars also depends on other ones, but what’s new is that with Jigsaw approach, we specify all the modules required with their versions, and the version specified is the used one, we can also specify a range of versions.

It’s true that Maven also provides an interesting way to specify dependencies between jars, but with Jigsaw we have more control and flexibility when defining module dependencies.

If we search for all types used by jndi, they must exist in the modules specified by requires section.

Java
from t in Types where t.IsUsedBy ("jndi")
select new { t, t.NbBCInstructions }

Image 3

As we can observe, all modules used are specified in the module specification.

provides

A service is a well-known set of interfaces and (usually abstract) classes. A service provider is a specific implementation of a service. The classes in a provider typically implement the interfaces and subclass the classes defined in the service itself.

A module can declare that it provides a service and specify the service provider by using the “with” keyword.

For example, for jndi, we have this line in its module declaration:

Java
provides service sun.net.spi.nameservice.NameServiceDescriptor 
with sun.net.spi.nameservice.dns.DNSNameServiceDescriptor;

What specifies that it provides the service sun.net.spi.nameservice.NameServiceDescriptor and the implementation is sun.net.spi.nameservice.dns.DNSNameServiceDescriptor.

We can search for all service providers of the sun.net.spi.nameservice.NameServiceDescriptor service:

Java
from t in Types where t.Implement ("sun.net.spi.nameservice.NameServiceDescriptor")
select new { t, t.NbBCInstructions }

Image 4

Only sun.net.spi.nameservice.dns.DNSNameServiceDescriptor from jndi implements this service.

exports

An exports clause in a module declaration makes the public types in the package it names available to other modules, so we can with Jigsaw defines boundaries, and not all public types could be used from other modules, we must explicitly specify which types are visible.

The jndi module exports many packages, what that means is only these exported types could be used from other modules.

Let’s search for all types from jndi used by other modules:

Java
from t in Projects.WithNameIn( "jndi").ChildTypes() 
where t.NbTypesUsingMe>0 && t.TypesUsingMe.Where
(a=>a.ParentProject.Name!="jndi").Count()>0
select t

Image 5

As we can observe, some packages are already specified in exports clause, but what about com.sun.jndi.toolkit.url, which is present inside exports clauses of the view section?

view

In large software systems, it is often useful to define multiple views of the same module. One view can be declared for general use by any other module, while another provides access to internal interfaces intended only for use by a select set of closely-related modules.

For example, with jndi, we want that com.sun.jndi.toolkit.url be visible only for cosnaming and kerberos modules, as specified in the module declaration.

Java
view jdk.jndi.internal {
    exports com.sun.jndi.toolkit.url.*;
    exports sun.net.dns.*;

    permits jdk.cosnaming;
    permits jdk.kerberos;
}

This way, we have more flexibility to define module boundaries.

And to check that only these two modules have access to com.sun.jndi.toolkit.url, let’s search for all types using this package.

Java
from t in Types where t.IsUsing ("com.sun.jndi.toolkit.url")
select new { t, t.NbBCInstructions }

Image 6

As we can observe only cosnaming module use it because it has the permission to do it.

With Jigsaw, a module could be very well specified, and maybe this new approach will remove the dependency hell between jars.

Of course, we can check dependencies by using tools, for example with CQLinq, we can add rules to do the same job as require, exports, provide clauses, but it’s better that it will be integrated in the JRE.

ModuleClassLoader

In the standard approach, we have two class loaders:

  • VM bootstrap class loader
  • System class loader

However, with the modular approach, we have:

  • VM bootstrap class loader (see later for what it does)
  • One loader per one or more modules
  • A module loader is used to start an application
  • Module loaders load their dependencies, e.g. java.base, that are lazily created when it loads a class.

Of course, we can always define our custom loader like OSGi does to have more control on their bundles.

Here’s a dependency graph showing some types involved when loading a module.

Image 7

Conclusion

When we discover the importance of the modular approach, we wonder why it was not implemented many years before? Why was it delayed each time? And why not use the mature OSGi instead of creating a new alternative?

Maybe in the future, we will have answers to all these questions, and Jigsaw will be a success in the Java world.

Image 8 Image 9

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)