Gradle: Building a modularized library that is compatible with Java 8

送分小仙女□ 提交于 2019-12-21 05:12:15

问题


So Java 9 is there, soon to be followed by Java 10. Time we should make our libraries ready for use in Java 9 projects. I did it in the following way:

  1. provide a module-info.java
  2. added the (experimental) jigsaw plugin in build.gradle
  3. Manually made changes according to the guide on the gradle site instead of using the jigsaw plugin.

So far, both approaches work fine, and I can use the generated Jar in Java 9 projects.

The problem is, the resulting Jar is not compatible with Java 8 although I used no Java 9 features except the module-info.java. When I set targetCompatibility = 8, an error message tells me to also set sourceCompatibility = 8 accordingly. Which then rejects the module-info.java for which I should set sourceCompatibility = 9.

How can this be solved?

I removed the jigsaw plugin again, and tried this, but am stuck:

  1. set sourceCompatibility = 8 and targetCompatibility = 8
  2. create a new source set moduleInfo that contains the single file module-info.java
  3. set sourceCompatibility = 9 and targetCompatibility = 9 for the new sourceset

Now compilation works, and Gradle uses Java 9 when it tries to compile the module-info.java. However, modules (in this case log4j) are missing, and I get this error:

:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:jar UP-TO-DATE
:sourcesJar UP-TO-DATE
:assemble UP-TO-DATE
:spotbugsMain UP-TO-DATE
:compileModuleInfoJava
classpath:
compilerArgs: [--module-path, , --add-modules, ALL-SYSTEM]
D:\git\utility\src\module-info\java\module-info.java:14: error: module not found: org.apache.logging.log4j
    requires org.apache.logging.log4j;
                               ^
warning: using incubating module(s): jdk.incubator.httpclient
1 error
1 warning
:compileModuleInfoJava FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileModuleInfoJava'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
5 actionable tasks: 1 executed, 4 up-to-date

This is the build.gradle used (Gradle version is 4.5.1):

plugins {
  id "com.github.spotbugs" version "1.6.0"
}

apply plugin: 'maven'
apply plugin: 'maven-publish'
apply plugin: 'java-library'
apply plugin: 'com.github.spotbugs'

sourceCompatibility = 8
targetCompatibility = 8

group = 'com.dua3.utility'

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
  compile     group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
  testRuntime group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'

  // Use JUnit test framework
  testImplementation 'junit:junit:4.12'
}

ext.moduleName = 'com.dua3.utility' 

sourceSets {
    moduleInfo {
        java {
            srcDir 'src/module-info/java'            
        }
    }
}

compileModuleInfoJava {
    sourceCompatibility = 9
    targetCompatibility = 9

    inputs.property("moduleName", moduleName)

    doFirst {
        options.compilerArgs = [
            '--module-path', classpath.asPath,
            '--add-modules', 'ALL-SYSTEM'
        ]
        classpath = files()  
        System.out.println("classpath: "+classpath.asPath)
        System.out.println("compilerArgs: "+options.compilerArgs)
    }
}

tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled false
        html.enabled true
    }
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

artifacts {
    archives sourcesJar
// fails with jigsaw:    archives javadocJar
}

defaultTasks 'build', 'publishToMavenLocal', 'install'

And this is module-info.java:

module com.dua3.utility {
    exports com.dua3.utility;
    exports com.dua3.utility.io;
    exports com.dua3.utility.jfx;
    exports com.dua3.utility.swing;
    exports com.dua3.utility.lang;
    exports com.dua3.utility.math;
    exports com.dua3.utility.text;

    requires javafx.controls;
    requires javafx.web;
    requires java.xml;
    requires java.desktop;
    requires org.apache.logging.log4j;
}

回答1:


OK, I finally got it working. In case anyone else wants to know how to do it, this is what I have done:

  • set the Java version to 8, so that the library will be usable by Java 8 applications:

    sourceCompatibility = 8
    targetCompatibility = 8

  • configure the module name

    ext.moduleName = com.dua3.utility

  • add a new sourceset consisting only of module-info.java:

     sourceSets {
            moduleInfo {
                java {
                    srcDir 'src/module-info/java'            
                }
            }
        }
    
  • set compatibility to Java 9 for the moduleInfo, sourceSet, configure modules, and set the output directory:

     compileModuleInfoJava {
        sourceCompatibility = 9    
        targetCompatibility = 9
    
    inputs.property("moduleName", moduleName)
    
    doFirst {
        classpath += sourceSets.main.compileClasspath
    
        options.compilerArgs = [
            '--module-path', classpath.asPath,
            '--add-modules', 'ALL-SYSTEM,org.apache.logging.log4j',
            '-d', sourceSets.main.output.classesDirs.asPath
        ]
    }
    }
    
  • configure the jar task to include moduleInfo:

    jar 
    {
      from sourceSets.main.output
      from sourceSets.moduleInfo.output
    }
    

In case you are using the SpotBugs plugin, you also have to configure the sourceSet explicitly because it will otherwise fail when it tries to process the ModuleInfo sourceSet.

I finally ended up with this version of build.gradle:

plugins {
  id "com.github.spotbugs" version "1.6.0"
}

apply plugin: 'maven'
apply plugin: 'maven-publish'
apply plugin: 'java-library'
apply plugin: 'com.github.spotbugs'

sourceCompatibility = 8
targetCompatibility = 8

group = 'com.dua3.utility'

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
  compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
  testRuntime group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'

  // Use JUnit test framework
  testImplementation 'junit:junit:4.12'
}

ext.moduleName = 'com.dua3.utility' 

sourceSets {
    moduleInfo {
        java {
            srcDir 'src/module-info/java'            
        }
    }
}

compileModuleInfoJava {
    sourceCompatibility = 9
    targetCompatibility = 9

    inputs.property("moduleName", moduleName)

    doFirst {
        classpath += sourceSets.main.compileClasspath

        options.compilerArgs = [
            '--module-path', classpath.asPath,
            '--add-modules', 'ALL-SYSTEM',
            '-d', sourceSets.main.output.classesDirs.asPath
        ]
    }
}

jar 
{
    from sourceSets.main.output
    from sourceSets.moduleInfo.output
}

spotbugs {
    sourceSets = [sourceSets.main]
}

tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled false
        html.enabled true
    }
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

artifacts {
    archives sourcesJar
    archives javadocJar
}

defaultTasks 'build', 'publishToMavenLocal', 'install'



回答2:


The question is over a year old, but in case anyone stumbles here, this functionality is now supported by Gradle Modules Plugin since version 1.5.0.

With this plugin, you don't have to create a custom source set, and you only need to call modularity.mixedJavaRelease method.

Here's a sample of how to apply the plugin to one's main build.gradle:

plugins {
  // your remaining plugins here

  id 'org.javamodularity.moduleplugin' version '1.5.0' apply false
}

subprojects {
  // your remaining subproject configuration here

  apply plugin: 'org.javamodularity.moduleplugin'
  modularity.mixedJavaRelease 8 // sets "--release 8" for main code, and "--release 9" for "module-info.java"

  // test.moduleOptions.runOnClasspath = true // optional (if you want your tests to still run on classpath)
}


来源:https://stackoverflow.com/questions/48928723/gradle-building-a-modularized-library-that-is-compatible-with-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!