Some notes on Java 9

Jigsaw

The part of Java 9 that deals with a new phenomenon called modules falls under the sobriquet, Jigsaw.

Because it's imminent (September, 2017), I followed Trisha Gee's presentation on Java 9. There are implications to this for work I'm doing presently. In particular, the disappearance of classpath. Trish bemoans this a little. Some technologies I use, such as NiFi and Cassandra, make use of classpath. So this interests me.

Project structure

Projects don't merely "pour over" into Java 9 from older versions. There's work to do. For one thing, module definition can no longer be willy-nilly.

Structure modules as separate IntelliJ submodules (or Eclipse projects/subprojects) with one package and module-info.java. E.g.: project sense-nine. I wonder what Eclipse is doing about this. Eclipse doesn't handle the concept of submodules or subprojects at all. Maybe this will have to change. Anyway, what me care?

sense-nine
 ├─ .idea
 ├─ com.mechanitis.demo.sense.client
 │   ├─ src
 │   │   ├─ com
 │   │   │   └ mechanitis
 │   │   │      └ demo
 │   │   │         └ sense
 │   │   │            └ client
 │   │   │               └ Java source files...
 │   │   └─ module-info.java
 │   └─ test
 │       └ com
 │          └ mechanitis
 │             └ demo
 │                └ sense
 │                   └ client
 │                      └ Java test files...
 └─ com.mechanitis.demo.sense.flow
     ├─ src
     │   ├─ com
     │   │   └ mechanitis
     │   │      └ demo
     │   │         └ sense
     │   │            └ flow
     │   │               └ Java source files...
     │   │                  └ impl
     │   │                     └ Java source files (classes will be publicly invisible, see below)...
     │   └─ module-info.java
     └─ testcommechanitisdemosenseflow
                        └ Java test files...
  etc.

Note that Gradle can't handle this (as of Trish's presentation), but Maven can. Still, I'm not sure how eager I am right now to create such projects in IntelliJ since they do defy traditional Maven (and ancient, traditional Java) structure. I would have welcomed it back in my Eclipse days.

The module-info.java file

module-info.java:
module com.mechanitis.demo.sense.flow
{
}

When the Java 9 compiler runs, it's no longer depending on the classpath, but on the modules you define. Now, you'll see, for instance, in the list of imports red ink for a class whose module hasn't been defined (in modules-info.java), let's say, import java.util.logging.Logger, so you Alt-click (in IntelliJ) the missing import and choose, for example, Add 'requires java.logging' statement to module-info.java, offered by the IDE. You then see in that file:

module-info.java:
module com.mechanitis.demo.sense.flow
{
  requires java.logging;
 // requires java.base; —you don't have to specify this; it's assumed!
}

So, moving a project's source to Java 9 is fraught with tedious duties. This said, those duties make you revisit your project structure (which can be tragically wrong if you publish it for consumption by other Java applications) and dependencies.

Now, there's a thing called, requires java.base, that you do not have to specify explicitly because it's just assumed. This is packages like java.util.

If you drill down through (in modules-info.java) a requirement, IntelliJ IDEA shows you the supplying JAR in External Libraries in the Project pane.

Exporting

If you want your module to export its classes for use by other modules or code, you explicitly list that in module-info.java. If you don't, it isn't exported and consuming code cannot see or use it:

module-info.java:
module com.mechanitis.demo.sense.flow
{
  requires java.logging;
  exports com.mechanitis.demo.sense.flow;
  // exports com.mechanitis.demo.sense.flow.impl; —don't export this!
}

This means that everything in the package, com.mechanitis.demo.sense.flow, will be exported from the module and available to consuming applications. To continue the example, if you want to avoid surfacing the code (and access to) of some package in your application, then you simply omit exporting it. That could be a subpackage in our example, such as we added separately a little higher up in our illustration, com.mechanitis.demo.sense.flow.impl.

There are also opens statements for module-info.java. It would appear that you can open your module to other non-base packages. Learn and use jdeps. Trish did not cover these and I can wait to figure out what they are and do. In the other reading I've done, mention has been absent.

Other interesting points...


Modules in Java 9...

In Java 9, which we're not yet using, so this is a little professional-development work here, you follow these steps to use modules.

Why should we use this feature?

  • Provide reliable configuration. The class path cannot expression relationships between components so, if missing, then this will not be discovered until run-time when an attempt to use it is made. Also, the class path allows classes in the same package to be loaded from different components leading to unpredictable behavior that's often very difficult to diagnose.
  • Strong encapsulation. The access-control mechanism of Java and the JVM provided no way for a component to prevent other components from accessing it's internal packages until this feature. The component uses module-info.java to specify which of its packages (by package path) are to be accessible and which are not.
  • Scalability. As Java has grown, it's become less well adapted for use in small devices because too much gets drawn into the link unintentionally and needlessly.
  • Greater integrity. Causual use of interfaces that aren't supposed to be external is a security risk and a maintenance burden.
  • Improved performance. More ahead-of-time, whole program optimization technique can be used and made more effective when it's known that a class can refer only to classes in a few components rather than just any class loaded at run-time.

Other notes.

  • There are many command-line options to java that give clarity to modularity.
  • Beginning in Java 9, Javadoc divides into modules instead of packages and there's a module graph inside.

List of useful links:

  1. Create module-info.java on the path of the package governed by the the definitions you want to place in it. Often, this is ${PROJECT-NAME}/src/main/java.
  2. The contents of this file will be
    module package-path
    {
    }