© Alexandru Jecan  2017

Alexandru Jecan, Java 9 Modularity Revealed, https://doi.org/10.1007/978-1-4842-2713-8_12

12. Integration with Tools

Alexandru Jecan

(1)Munich, Germany

In order for Java 9 to be adopted easily and as quickly as possible by the developer community, it’s very important for the integrated development environments (IDEs) and build tools to offer extensive support for Java 9 as much as possible—so important that we dedicate this entire chapter to this topic.

This last chapter shows how JDK 9 in general and the Java Platform Module System in particular integrates with the following:

  • IDEs like Intellij IDE, Eclipse, and NetBeans

  • Build tools like Apache Maven

We’ll discover what kinds of support these tools offer for Jigsaw.

Integration with IDEs

Jigsaw is already integrated in IDEs like Intellij IDEA, Eclipse, and Netbeans. The next three subsections cover what kind of support these IDEs offer to make the work with Jigsaw easier for developers. We’ll start with Intellij IDEA.

Note

Intellij IDEA, Eclipse, and NetBeans are among the most popular IDEs for Java programming according to an article published on July 2017, at www.keycdn.com/blog/best-ide/ . So we decided to focus on these three IDEs in this chapter instead of other IDEs that don’t especially focus on the Java programming language.

Integration with Intellij IDEA

Intellij IDEA, developed by JetBrains, is a Java IDE that has both a community edition and a commercial edition. It offers support for Project Jigsaw starting from version 2017.1, released in March 2017. Among its many features, IDEA supports code completion inside the module-info.java module descriptor file.

Figure 12-1 shows how we can create a module-info.java file in Intellij IDEA by selecting New ➤ module-info.java .

A431534_1_En_12_Fig1_HTML.jpg
Figure 12-1. Add a module-info.java in Intellij IDEA

IDEA creates an empty module-info.java file that contains only the module keyword and a name for the module.

If we add a new import into a java file, Intellij IDEA can automatically add the necessary requires clause inside the module-info.java. For example, if we import the java.sql.DriverManager class in our code, Intellij IDEA can find out the name of the module where this class resides. As a result, it can indicate to us to add the requires java.sql clause inside the module descriptor, as illustrated in Figure 12-2.

A431534_1_En_12_Fig2_HTML.jpg
Figure 12-2. Autocomplete function for adding a requires statement inside the module-info.java

Intellij IDEA also provides code autocomplete functionality inside the module-info.java file. If we start to type the name of a module, IDEA will be compute and show the available suggestions, as shown in Figure 12-3.

A431534_1_En_12_Fig3_HTML.jpg
Figure 12-3. Autocomplete for the module names

Intellij IDEA can also provide autocomplete functionality for the packages we want to export. Figure 12-4 shows an example of providing the autocomplete feature for the exports clause. When we start to type the name of the package we want to export, Intellij IDEA can indicate likely suggestions so we don’t have to type the entire name.

A431534_1_En_12_Fig4_HTML.jpg
Figure 12-4. Autocomplete function for the names of the packages inside the module-info.java file

Among other features related to Jigsaw that Intellij IDEA offers, we want to mention these:

  • Visualizing module diagrams: Module diagrams allow us to visualize the dependencies between our modules. These can be visualized by selecting Diagrams ➤ Show Diagram ➤ Java Modules Diagram.

  • Visualizing module usages: Shows where a module is used.

Intellij IDEA provides many other features not covered in this chapter. Covering all the features is beyond the scope of this book. For more on Jigsaw support in Intellij IDEA, check out the documentation on the official JetBrains blog, at https://blog.jetbrains.com/idea/?s=java+9 . Search for the keywords java 9 or module.

The next section explores another popular IDE: Eclipse.

Integration with Eclipse

Eclipse is a free IDE. As of JDK 9 build 178 (July 2017), Eclipse offers a useful tool called Java 9 Support for Oxygen that works only with Eclipse Oxygen (4.7).

However, it’s possible to start every version of Eclipse with JDK 9, and there are two possibilities for doing that. The first is to have JDK 9 on the system path, and the second is to add the path to JDK 9 in the eclipse.ini file, as in the following example:

--launcher.appendVmargs
-vm
C:Program FilesJavajdk-9injavaw.exe

Eclipse can be started using JDK if you’re using a version greater or equal to Eclipse 4.7. If you’re using a version prior to Eclipse 4.7, you have to add the flag --add-modules=ALL-SYSTEM inside the eclipse.ini file. This flag has been added in eclipse.ini in Eclipse 4.7, so you don’t have to add it anymore if you’re using Eclipse 4.7 or higher. The ALL-SYSTEM flag is used because not all the types that Eclipse uses reside inside the java.base module.

As for the Java 9 Support for Oxygen tool, the Eclipse documentation states: “Eclipse Java 9 Support contains the following: ability to add JRE and JDK 9 as installed JRE, support for JavaSE-9 execution environment, ability to create Java and Plug-in projects that use a JRE or JDK 9, ability to compile modules that are part of a Java project.”

The support of Java 9 for Eclipse is still work in progress as of August 2017. For more information on Jigsaw support in Eclipse, check the documentation on the official Eclipse Wiki at https://wiki.eclipse.org/Java_9_Readiness .

Integration with NetBeans

Netbeans is a cross-platform IDE developed by Oracle. It offers support for JDK 9 starting from Netbeans version 9. As of August 2017, NetBeans lets us create only one single module inside a NetBeans project—we can’t create more than one module into a single NetBeans project. If we have more than one Jigsaw module, we have to create a separate NetBeans project for each module.

NetBeans 9 is still under development as of August 2017. You can download it from http://bits.netbeans.org/download/trunk/nightly/latest/ .

If we have only JDK 9 installed on our system, then it’s fine for NetBeans 9, but if we have JDK 9 and another JDK version <9 installed on our system, we have to explicitly specify during the installation of NetBeans that we want to use JDK 9.

According to the official NetBeans website, here are the most important areas where NetBeans JDK 9 offers support :

  • Maven projects

  • module-info.java support

  • Compilation

  • Run and debug

  • Module dependency graph

Note

For more information on JDK 9 integration with NetBeans, visit http://wiki.netbeans.org/JDK9Support .

You just got an overview of the support that three of the most popular Java-related IDEs give for Project Jigsaw. The next section talks about Jigsaw integration with build tools like Apache Maven.

Integration with Build Tools

Apache Maven has provided very good integration for Jigsaw since the first half of 2016. It started integrating Jigsaw very early and collected valuable feedback from the developer community. The Maven team also developed a great Apache Maven JDeps plugin for running JDeps from Maven.

Integration with Apache Maven

One of the primary goals of Maven was to upgrade only its plugins in order to offer support for Java 9. No changes were necessary inside the Maven Core for making Maven run on Java 9. Another primary goal was to offer support for Java 9 starting with Maven 3.0.

In order to use Maven with Java 9, two conditions have to be met simultaneously:

  • The JAVA_HOME variable for Maven has to be set to point to a JDK 9 installation.

  • The source and target of the Maven Compiler plugin should be greater or equal than 6.

The Maven Compiler plugin defines a parameter for source and a parameter for target that correspond to the version of the JDK. The minimum supported version for the source and target for JDK 9 is 6. The version of JDK used to run Maven doesn’t necessarily have to be the same as the version of JDK used to run the Maven Compiler plugin.

Maven needed adjustments for some of the JEPs implemented in Java 9. Besides the JEPs related to Jigsaw, Maven also needed adjustments in order to fit the following JEPs: JEP 223 – New Version-String scheme, JEP 226 – UTF-8 Property Files, JEP 238 – Multi-Release JAR files, JEP 247 – Compile for Older Platform Versions, and JEP 285 – Modular Java Application Packaging.

Even if it’s not part of Jigsaw, we should say something about the JEP 223 – New Version-String scheme because it has huge impact on Maven. Maven relies heavily on the system properties. Since the version string has changed in Java 9, Maven throws an ArrayIndexOutOfBoundsException as it internally tries to compute the version. Fortunately, the issue has been fixed starting with the following versions of the following plugins:

  • maven-archiver-3.0.1

  • maven-jar-plugin-3.0.0

  • maven-war-plugin-3.0.0

  • maven-ear-plugin-xxx

  • maven-javadoc-plugin-2.10.4

If you’re using these plugins in Java 9, make sure to upgrade them to at least one of these versions.

Table 12-1 shows the Maven plugins affected by the introduction of Java 9.

Table 12-1. Maven Plugins Affected by Java 9

Plugin Name

Minimum Compatible Version

Affected Goal and Status

Maven Compiler plugin

3.6.1

compile => new feature

testCompile => new feature

Maven Javadoc plugin

2.10.4

jar => failure

javadoc => warning

aggregate => failure

Maven Plugin plugin

3.5

descriptor

Maven War plugin

 

war => failure

Plexus :: Component Metadata

1.7

generate-metadata => new feature

Remember the JDeps tool described in Chapter 8? Maven integrates this tool into a new plugin, the Apache Maven JDeps plugin.

Apache Maven JDeps Plugin

This plugin makes use of the JDeps tool to analyze internal API calls inside our classes. It can perform analysis when building a project.

Note

The first version of the Maven JDeps Plugin is 3.0. This version has been chosen deliberately by Maven to reveal that Maven 3.0 or greater should be used.

The plugin consists of two goals :

  • A goal called jdeps:jdkinternals that verifies whether the main classes depend on internal JDK classes

  • A goal called jdeps:test-jdkinternals that verifies whether the test classes depend on internal JDK classes

Table 12-2 shows some of the most important options that can be used inside the <configuration> tag of the Maven JDeps plugin, as recorded in the Oracle documentation for Java SE.

Table 12-2. Options for the Maven JDeps Plugin

Plugin Name

Description

Example

failOnWarning

Specifies whether the build continues if there are JDeps specific warnings. Default is true

<failOnWarning>

    false

</failOnWarning>

dependenciesToAnalyzeIncludes

Specifies additional dependencies to be analyzed. The format is

<include>

    groupId:artifactId

</include>.

Patterns are allowed.

<dependenciesToAnalyzeIncludes>

    <include>*:*</include>

    <include>

        com.apress.*:*

    </include>

    <include>

        com.apress.book:*

    </include>

    <include>

        com.apress.book:utils

    </include>

</dependenciesToAnalyzeIncludes>

dependenciesToAnalyzeExcludes

Specifies dependencies that shouldn’t be analyzed. The format is

<exclude>

    groupId:artifactId

</exclude>.

Patterns are allowed.

<dependenciesToAnalyzeExcludes>

    <exclude>

        com.apress.book:*

    </exclude>

</dependenciesToAnalyzeExcludes>

jdeps.include

Restricts analysis to classes that are matching the pattern. It filters the list of classes to be analyzed.

 

jdeps.profile

Shows profile or the file containing a package.

 

jdeps.recursive

Traverses all dependencies recursively.

 

jdeps.module

Shows the module containing the package.

 

Running with the option - R results in warnings being displayed if there are transitive dependencies that are making use of JDK internal APIs.

Note

By setting the <failOnWarning> option to true, the build will immediately fail if there are any warnings.

If we have an application that uses third-party libraries, it would make sense first to find the JDK internal APIs inside our application code using the Maven JDeps plugin with option <failOnWarning> set to true so that the build fails if any JDK internal APIs are found. In the next step we could run the Maven JDeps plugin only on our third-party libraries, but this time setting <failOnWarning> to false so that our build doesn’t fail if the third-party libraries are using JDK internal APIs. This is reasonable because we can’t dig inside the third-party libraries to fix them, but we can do this inside our own application code.

Listing 12-1 shows an example of using the Maven JDeps plugin to implement this specific use case.

Listing 12-1. Example Using the Maven JDeps Plugin
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jdeps-plugin</artifactId>
    <version>3.0.0</version>
       <executions>
          <execution>
             <id>testOnClasses</id>
             <goals>
                <goal>jdkinternals</goal>
                <goal>test-jdkinternals</goal>
             </goals>
          </execution>
          <execution>
             <id>testOnDependencies</id>
             <goals>
                <goal>jdkinternals</goal>
                <goal>test-jdkinternals</goal>
             </goals>
             <configuration>
               <failOnWarning>false</failOnWarning>
               <recursive>true</recursive>
             </configuration>
          </execution>
       </executions>
</plugin>

We search for JDK internal APIs inside our application code in the execution block which we named testOnClasses. We specified both goals, jdkinternals and test-jdkinternals, so that both main and test classes are verified. We didn’t specify the <failOnWarning> attribute here, so it will default to true. Afterward, we specify another execution block to search our third-party libraries that are attached to our application. For this, we specify the <recursive> tag as true. failOnWarning is set to false so the build doesn’t fail in case we find a JDK internal API.

The next section explores the support that the Maven Compiler plugin offers for Jigsaw.

Apache Maven Compiler Plugin

The Apache Maven Compiler plugin offers support for the new Java Platform Module System starting with version 3.6.0, released in October 2016.

The version of the Apache Maven Compiler plugin can be specified directly in the plugin’s configuration:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.6.0</version>
</plugin>

Version 3.6.0 of the Apache Maven Compiler plugin added support for the module path. As we already know, the Maven Compiler plugin has two goals: compile and test-compile. During the compile phase, when a module-info.java file is found, the plugin will automatically switch to the module path. During the test-compile phase, the plugin will switch to the module path for the main sources and to the class path for the test sources.

Note

The Maven team also added support for specifying flags like --add-modules or --add-exports directly inside the pom.xml configuration.

For instance, if we want to use the --add-modules flag to add the module java.xml.bind using the Maven Compiler plugin, we could define this inside the configuration of the Maven Compiler plugin:

<compilerArgs>
    <arg>--add-modules</arg>
    <arg>java.xml.bind</arg>
</compilerArgs>

We could also use Maven to make the sun.net package from module java.base available to our module com.apress.myModule:

<compilerArgs>
    <arg>--add-exports</arg>
    <arg>java.base/sun.net=com.apress.myModule</arg>
</compilerArgs>

Listing 12-2 shows the entire configuration of the plugin for the two use cases mentioned earlier:

Listing 12-2. Adding Compiler Arguments to the Maven Compiler Plugin
<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.6.0</version>
    <executions>
      <execution>
        <id>example</id>
        <goals>
           <goal>compile</goal>
        </goals>
        <configuration>
           <compilerArgs>
              <arg>--add-exports</arg>
              <arg>java.base/sun.net=com.apress.myModule</arg>


              <arg>--add-modules</arg>
              <arg>java.xml.bind</arg>
           </compilerArgs>
        </configuration>
      </execution>
    </executions>
</plugin>

In this example, we defined the version of the maven-compiler-plugin to be 3.6.0. Inside the <compilerArgs> XML tag, we specified arguments that we want to be passed to the compiler. Each argument is specified inside the <arg> XML tag .

Backward Compatibility

During migration to Java 9, projects written in a Java version <8 will get a module-info.java file. With Maven, it’s possible to compile these projects in Java 9 (taking the module-info.java file into account) or compile them in versions prior to Java 9.

For this, two compilations have to be made:

  • The first compilation will be executed by the Maven Compiler plugin using the configuration <release>9</release>.

  • The second compilation will be executed by the Maven Compiler plugin using a configuration lower than 9, for instance: <source>1.8</source> and <target>8</target>.

This can be easily executed by the Maven Compiler in two different execution blocks. If we want to be compatible with a version prior to JDK 6, we have to use different JDKs. That’s because JDK 9 doesn’t support compilation for versions prior to JDK 6.

The Maven Compiler plugin also offers support for JEP 247 – Compile for Older Platform Versions. It allows us to add a module-info.java file for Java 9 projects and also be compatible with earlier versions of Java. For this, we need to call javac twice. First we need to call javac with release=9 in order to compile the module-info.java file with JDK 9. Then we need to set the source and target to a lower version of Java in order to compile the rest of the source code with a lower Java version. If we’re using at least Maven version 3.3.1, we can use toolchains for achieving this use case.

For instance, if our JAVA_HOME environment variable is lower than or equal to JDK 9, we can set the version of the jdkToolchain to 9 in order to compile everything, including the module-info.java file:

<configuration>
    <jdkToolchain>
        <version>9</version>
    </jdkToolchain>
    <release>9</release>
</configuration>

Subsequently, we recompile the files and exclude the module-info.java file:

<configuration>
    <excludes>
        <exclude>module-info.java</exclude>
    </excludes>
</configuration>

On the other side, if our JAVA_HOME environment variable is equal to JDK 9, then we could set the version of the <jdkToolchain> to [1.5,9) and compile the files with <source> and <target> = 1.5:

<jdkToolchain>
    <version>[1.5,9)</version>
</jdkToolchain>
    <source>1.5</source>
    <target>1.5</target>
Note

As a rule, we should compile with the matching JDK version.

To configure the Maven Toolchain plugin, we could edit the toolchains.xml file in the .m2 folder or, if we’re using a version of Maven greater of equal to 3.3.1, we could directly edit the toolchains.xml file inside the Maven conf directory.

Maven also defines a new command-line option --release, which lets us pass the version of the JDK release that we want to compile with. For example, the option --release 8 is equivalent to -source 8 -target 8 -bootclasspath .... The Maven Compiler plugin starting with version 3.6.0 specifies the release version like this:

<release>release_version</release>

The <release> tag configuration has greater precedence over the <source> and <target> tags. As a result, if we specify the <release> tag as well as the <source> and <target> tags, then the <release> tag will be taken into consideration.

Note

Version 3.6.1 of the Apache Maven Compiler plugin was introduced in January 2017.

We would also like to recommend an interesting article written by Robert Scholte, the chairman of the Maven project, which explains why Maven is unable to automatically generate the module-info.java file. You can read it at www.sitepoint.com/maven-cannot-generate-module-declaration/ .

Summary

In this chapter we saw what kind of support IDEs and build tools provide for Jigsaw. We started by briefly talking about three IDEs: Intellij IDEA, Eclipse, and NetBeans.

Then we switched to build tools and looked at the support Maven provides for JDK 9. We talked about backward compatibility with Maven and learned how the Java Compiler is called twice—once because the module-info.java file has to be compiled with --release 9, and once again so that all the Java sources except module-info.java are compiled with source and target less than 9. We also learned about the Maven JDeps plugin, which is used to find usages of JDK internal APIs throughout our code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.182.159