Lead Image © Krockenmitte, photocase.com

Lead Image © Krockenmitte, photocase.com

Finally: Java 9

Land Ho!

Article from ADMIN 37/2017
Java 9 tempts programmers with innovations intended to facilitate the development and operation of Java applications.

For a long time, Java [1] has easily topped the rankings of popular programming languages. This is not surprising; after all, programs developed in Java can be used anywhere from cellphones to mainframes and across all operating systems. However, a glimpse at the former shooting stars Perl and PHP shows that there is no guarantee of permanently riding atop the heap.

Regular updates help keep the language at the cutting edge and the estimated nine million Java programmers happy, but they have needed patience, because major release 9 has taken its time. Originally, it was planned as an interim release to deliver to the themes that were not ready in time for Java 8.1. "As quickly as possible" originally meant mid-2015, then mid-2016, and finally 2017. It remains to be seen whether the project schedule will be followed this time, although test builds are now available online [2].


One core feature of Java 9 par excellence is the Java Platform Module System that became known as Project Jigsaw [3]. Thus far, the Java compiler and the run-time environment have thrown all available libraries from the class path into a large pot. Whether this turns out to be a tasty soup or smoke and mirrors partly depends on subtle changes in the class path.

Many developer hours have been spent in class path hell battling against the class loader. The problem is, only the right libraries and library versions in the appropriate order result in a working application. Approaches such as Maven, ServiceLoader or OSGI only partially mitigated the situation and had to take a wide detour around the standard libraries.

With Jigsaw, this should be different. The new modular system pervades the entire stack of the compiler, from the Java Runtime Environment (JRE) and the standard libraries to the application libraries. The development effort for Jigsaw was originally estimated to be about size XL, but in the real world, a number of Xs were added. The initial plans had their sights set on Java 7.1; ultimately, Jigsaw now first appears in Java 9. All three affected versions were delayed by years.

Totally Modular

The result is not only improved handling of libraries, but modularization also allows developers to tailor the JRE to the needs of an application. After all, the standard libraries in Java 8 weigh in at around 60MB and 20,000 classes. They not only need space on the hard drive, but the computer also needs to load them into memory at every startup and check the classes and methods they contain. Less powerful machines (industrial automation, IoT, network appliances) welcome every single megabyte saved, so the application uses less space and launches faster.

Java 9 dismantles the monolithic standard library modules. If you do not need features such as the CORBA stack, the JavaScript interpreter, or encrypted XML documents, you will soon have the opportunity to tailor the installation to your own needs for the first time.

A Scenario

The scenario shown in Figure 1 is used as an illustration of the new modular strategy. The sample application consists of two proprietary modules (modulea and app). Also on board are two modules from Java itself and another two for logging.

Figure 1: Module dependencies with Jigsaw in a sample scenario.

The modulea module includes everything related to the Customer business object. It contains a Customer interface, the matching CustomerService for searching and saving, and the associated implementation (Impl) classes. For this purpose, the software needs classes from the modules java.core, java.xml, and slf4j.core. The app module contains the application itself and requires modulea plus logback.core; the modules required in moda are implicitly available.

At the file level, modules are ordinary Java archives in JAR format that additionally contain a description of the module. They each provide module_info.java files that the developer compiles with the other classes and bundles into the JAR.

Listing 1 shows the module description for modulea. The declaration starts with the module keyword; the requires point to the code to the necessary modules. The compiler and the JRE use this to load the modules or to inform the user that they are missing immediately on startup. For modules like app to be able to use the two interfaces, the module description releases the contained package using export.

Listing 1

modulea description

01 module de.lm.java9.modulea {
02     // required
03     requires java.base;
04     requires java.xml;
05     requires slf4j.api;
07     // exported
08     exports de.lm.java9.modulea;
10     // provides a service implementation
11     provides de.lm.java9.modulea.CustomerService with de.lm.java9.modulea.intern.CustomerServiceImpl;
12 }

All other classes from modulea are not visible outside of the module. Although the CustomerImpl class is declared as public, the contained package cannot be reached outside of the module because of a missing export. In this way, developers could enforce loose coupling so that the user of a library sees its interfaces but has no access to the actual implementation or helper classes.

Ultimately, access to the object instances of the exported interfaces are needed somehow. Putting the CustomerService implementation in the public package would be contrary to the idea of loose coupling, because a user of the objects should not have to worry about how this is implemented. Here, the well-known but little-used ServiceLoader enters the scene as a solution. It can be used to query a CustomerService instance without knowing or accessing its implementation. Its application is shown in Listing 2, in which the main application queries CustomerService without knowing anything about the related implementation class.

Listing 2

ServiceLoader application

01 // Create the ServiceLoader for a CustomerService
02 ServiceLoader<CustomerService> sl
03         = ServiceLoader.load(CustomerService.class);
05 // Use first implementation
06 CustomerService service = sl.iterator().next();
08 set<Customer> customer = service.search("Tux*");

ServiceLoader thus acts as a broker between different modules. To do so, the providing module must publish the implementation using the provides keyword (Listing 1, line 11), and the module that is using it must publish it via uses (Listing 3, line 7).

Listing 3

app description

01 module de.lm.java9.app {
02     // required
03     requires de.lm.java9.modulea;
04     requires logback.core;
05     requires logback.classic;
06     // uses Service
07     uses de.lm.java9.modulea.CustomerService;
08 }

Java 9 breaks down the normal run-time library into 96 small modules, such as java.core and java.xml. It is comparatively easy to switch your own applications to the new module concept; libraries used for this purpose do not usually need to support it immediately. Instead, it is typically fine to add the normal JARs to the module path (e.g., slf4j or logback). They are then available as modules in automatic mode.

Normal visibility rules from the class definition apply (private, package, public). The module names each derive from the names of the JAR files. Through the use of these names, they can be used by real modules in named mode with a module description.

If you use dirty hacks like Class.forName or load resources across JARs, you will not be able to get your application running on Java 9 without making changes. This means moving to the new strategy, or at least building a bridging module that combines the old and new worlds.

All told, the wait for Jigsaw seems to have been worthwhile. For example, the dependencies and published interfaces can now be cleanly defined and evaluated throughout the entire life cycle, from compiling through run time. Developers can force loose coupling for the first time using the ServiceLoader mechanism and the different visibilities inside and outside a module.

The modular run-time environment itself allows for a smaller memory footprint on less powerful hardware. Class.forName also causes comparatively little pain. The downside is the lack of support for module versions as offered by Maven. The only escape route here is to manipulate the module name as in modulea_v1, modulea_v2, and so on.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus