简体   繁体   中英

How to use maven with both jigsaw and jre 8 support?

I'm building a java project with maven. I want to make sure several things:

  1. the built jar CAN run on jre8.
  2. the built jar CAN run on jre9, with module/jigsaw.
  3. the built jar CAN be put on maven central.

How should I configure the maven-compiler-plugin? thanks.

the original repo is at https://github.com/cyanpotion/SDL_GameControllerDB_Util

right now I can pass 2 and 3, but the output jar seems cannot run on jre8.

A multi-release jar can be used to accomplish this purpose; however, if you are only after Jigsaw module support, a dual compilation configuration of Java 8 and 9 with the maven-compiler-plugin is sufficient (demonstrated below).

The following is a build configuration that is able to maintain JRE 8 support, but is compatible with being used as a module in JRE 9+. This can be tweaked to support a project as far back as JRE 1.6, if necessary.

Overview of the following build configuration :

  • Enforce a $JAVA_HOME JDK 9+ so that module-info.java can be compiled and validated against the sources (ensures that all module dependencies are correctly referenced).
  • Changes the default-compile execution to NO-OP. By specifying <release>8</release> (or target / source flags), some IDEs during Maven auto-importation (tested with IntelliJ) will assume the language level for this project is Java 8, and produce errors about the project's module-info.java .
  • Compiles all sources (including module-info.java ) for Java 9; this ensures that the module-info.java includes any dependencies used without the project sources.
  • Compile all sources ( excluding module-info.java ) for Java 8, overwriting all previously compiled Java 9 classes with Java 8 classes; this means the only Java 9 class (class level 53+) will be module-info.class . All other classes should now be executable on a compliant JRE 8.

Notes :

  • A caveat is this will compile sources twice , once for Java 8 and another for Java 9. This may significantly increase build times for larger projects (but negligible for smaller projects). This may resolved by placing module-info.java in another source directory (eg src/main/java9 ) and configuring a multi-release JAR (see the first link at the beginning of this message). Note that for proper IDE auto-importation and marking this additional Java 9 source directory correctly, a NO-OP execution with org.codehaus.mojo:build-helper-maven-plugin can be used.
  • Only module-info.java will have Java 9 support, all other classes are limited to classes/methods/fields/code available in JDK/JRE 8.
  • Some tooling may need to be updated in your project configuration if it does not support Java 9 module-info.class . Some older variants of the default Maven plugins do not have sufficient support for modules.
<build>
    <plugins>
        <!-- ensure the project is compiling with JDK 9+ -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>3.0.0-M3</version>
            <executions>
                <execution>
                    <id>enforce-jdk9</id>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                    <configuration>
                        <rules>
                            <requireJavaVersion>
                                <version>[1.9,)</version>
                                <message>JDK 9+ is required for compilation</message>
                            </requireJavaVersion>
                        </rules>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- compile sources -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <executions>
                <!-- disable default phase due to fixed id and position in lifecycle -->
                <execution>
                    <id>default-compile</id>
                    <phase>none</phase>
                    <!-- specify source/target for IDE integration -->
                    <configuration>
                        <release>9</release>
                    </configuration>
                </execution>
                <!-- compile sources with Java 9 to generate and validate module-info.java -->
                <execution>
                    <id>java-9-module-compile</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <configuration>
                        <release>9</release>
                    </configuration>
                </execution>
                <!-- recompile sources as Java 8 to overwrite Java 9 class files, except module-info.java -->
                <execution>
                    <id>java-8-compile</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <configuration>
                        <!-- specify JDK 9+ release flag to ensure no classes/methods later than Java 8 are used accidentally -->
                        <release>8</release>
                        <!-- exclude module-info.java from the compilation, as it is unsupported by Java 8 -->
                        <excludes>
                            <exclude>module-info.java</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

I've done it. See my project, the IPAddress Java library . You compile with Java 9 compiler level, then you recompile everything except the module-info.java with Java 8 compile level.. So you have a Java 8 jar with a Java 9 module-info. You can see the compile commands in my ant xml script on GitHub.

There was originally an issue with Android studio that has since been resolved, it would not ignore the module-info. More recent Android studio versions are fine, and so are all Java platforms and environments. Java 9 jres and up will recognize the module-info, Java 8 will not, Java 8 and earlier will ignore it.

My jar is also in maven central, so it is satisfying your 3 requirements. Try it out in your dev environment to see it work, using Java 8 or later jres.

Multi-release jars are not necessary and not worth the trouble.

When I was researching this same question I found this same solution in use with an Apache project, so I am not the only one doing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM