One of the most anticipated events of the Java world is going to be when version 9 gets released on the 21st of September. It’ll be a game changer, no doubt about that, primarily due to its module system. It can put an end to the jar-hell we might have been facing for a long time. In this short tutorial, I’d like to show you how a new Java 9 enabled Maven project can be configured.
The GA release was originally expected to be made available on the 27th of July, however Mark Reinhold has requested another 8 weeks delay in order to go over all the JCP processes.
You can find a sample project here: https://github.com/springuni/springuni-java9.
We could have created multi module projects in Maven (and also with Gradle, Ant, etc.) in the past as well, however they weren’t modules strictly speaking. Altought they appeared to be separate code bases, there was no standard way to define which functionalities those module provided and required. With build systems you could declare dependencies, but modules themselves didn’t take care of managing their own dependencies and offered services.
In large projects developers quickly experienced the jar-hell when multiple versions of the same library got pulled in as a side effect of transitive dependencies.
The way how Java 9 changes mitigates this is that you can now formally declare modules with
module-info.java
which encapsulates the following pieces of
information.
Lots of well known libraries are expected to migrate to Java 9’s module system and as a result they can share their public API and hide their internals with this mechanism.
There’s one caveat however, what are you going to do if you need to use such a library in the future which hasn’t been made available as a module yet? That’s a legitimate question indeed and here come the module types into play.
Modules are just plain old JAR files as before, but as of Java 9 they will contain a special module-info.java I mentioned above. There’s also a new concept called the module-path, which is a sibling of the well known class-path.
Having that said there are four module types:
Build tools like Maven has to handle the new constructs of the JDK, that is, module-info.java
and module path.
They have a Wiki page which lists all the plugin
requirements for Java 9.
In order to be able to work with JDK 9’s module system maven-compiler-plugin
version 3.6.1 or later is required.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
This is more or less optional, however I’d strongly recommend to use it. Java 9 hasn’t been released yet, we’re still using
Java 8 (or maybe Java 7) for production projects and it’s uncomfortable changing all the environment variables and point
them to a JDK 9’s home directory all the time we want to experiment with it. maven-toolchains-plugin
enables you to
use various environment effortlessly instead.
Create $HOME/.m2/toolchains.xml
(or %USERPROFILE%\.m2\toolchains.xml
on Windows) if you haven’t had it yet.
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>9</version>
<vendor>oracle</vendor>
</provides>
<configuration>
<!-- Change path to JDK9 -->
<jdkHome>/opt/oracle/jdk-9</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>oracle</vendor>
</provides>
<configuration>
<jdkHome>/opt/oracle/jdk-1.8.0.65</jdkHome>
</configuration>
</toolchain>
</toolchains>
Change the path to your actual JDK installation. After that the toolchains plugin can be added to your project.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<configuration>
<toolchains>
<jdk>
<version>9</version>
<vendor>oracle</vendor>
</jdk>
</toolchains>
</configuration>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
</plugin>
As of JDK 9 b72, a new feature became available: the
javac --release
command line option.
In brief, to use javac
to cross-compile to an older release of the platform it is not sufficient to just set the -source
and -target
options to the older value; the bootclasspath
must also be set to correspond to the older release too.
Setting the bootclasspath
was often forgotten and acquiring the needed information could be inconvenient.
The --release
flag in javac
addresses both of these shortcomings. Only a single flag needs to be set to cross compile
compared to three flags (source
, -target
, -bootclasspath
) and the needed information is included in the JDK. The
accepted argument values for --release
are 6, 7, 8, and 9.
<properties>
<maven.compiler.release>9</maven.compiler.release>
<maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>1.9</maven.compiler.target>
...
</properties>
Property maven.compiler.release
is directly mapped to the --release
flag of javac
, while the other two properties
are only necessary for IntelliJ to understand source compatibility.
Unfortunately there are test compilation failures at the time of writing. This is due to a breaking change introduced by
JDK-8178012, which removed of the -Xmodule
compiler flag. Hopefully MCOMPILER-294 gets fixed soon, in the
meantime however, compiling test sources can be disabled.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<!--
Fix breaking change introduced by JDK-8178012: Finish removal of -Xmodule
Reference: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8178012
-->
<executions>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
<configuration>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
That’s all folks!
If you want to learn more about Java 9, you can also check these Java 9 Tutorials from Java Code Geeks.
If you like Java and Spring as much as I do, sign up for my newsletter.