【问题标题】:Gradle: Building a modularized library that is compatible with Java 8Gradle:构建与 Java 8 兼容的模块化库
【发布时间】:2018-02-22 13:32:51
【问题描述】:

Java 9 已经存在,Java 10 很快就会紧随其后。是时候让我们的库准备好在 Java 9 项目中使用了。我是通过以下方式做到的:

  1. 提供一个module-info.java
  2. build.gradle 中添加了(实验性)jigsaw plugin
  3. 根据 gradle 站点上的guide 手动进行更改,而不是使用拼图插件。

到目前为止,这两种方法都可以正常工作,我可以在 Java 9 项目中使用生成的 Jar。

问题是,生成的 Jar 与 Java 8 不兼容,尽管我没有使用除 module-info.java 之外的 Java 9 功能。当我设置targetCompatibility = 8 时,一条错误消息告诉我也相应地设置sourceCompatibility = 8。然后拒绝我应该设置sourceCompatibility = 9module-info.java

如何解决?

我再次删除了拼图插件,并尝试了这个,但卡住了:

  1. 设置sourceCompatibility = 8targetCompatibility = 8
  2. 创建一个新的源集moduleInfo,其中包含单个文件module-info.java
  3. 为新的源集设置sourceCompatibility = 9targetCompatibility = 9

现在编译工作正常,Gradle 在尝试编译 module-info.java 时使用 Java 9。但是,缺少模块(在本例中为 log4j),我收到此错误:

: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

这是使用的build.gradle(Gradle 版本是 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'

这是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;
}

【问题讨论】:

  • 或许log4j依赖需要在api配置而不是implementation配置中声明?
  • 哦,是的,当compile 不起作用时,我更改了它。即使compile 适用于完整的 Java-9 版本。我现在试了一下,不管我设置什么(compileapiimplementation),错误仍然是一样的。我把它改回compile,因为我知道整个项目都设置好了到 Java 9。

标签: java gradle build.gradle java-9 java-platform-module-system


【解决方案1】:

好的,我终于搞定了。如果其他人想知道该怎么做,这就是我所做的:

  • 将 Java 版本设置为 8,以便 Java 8 应用程序可以使用该库:

    sourceCompatibility = 8
    目标兼容性 = 8

  • 配置模块名称

    ext.moduleName = com.dua3.utility

  • 添加一个仅包含 module-info.java 的新源集:

     sourceSets {
            moduleInfo {
                java {
                    srcDir 'src/module-info/java'            
                }
            }
        }
    
  • 为 moduleInfo、sourceSet 设置与 Java 9 的兼容性,配置模块,并设置输出目录:

     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
        ]
    }
    }
    
  • 配置jar 任务以包含moduleInfo

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

如果您使用SpotBugs 插件,您还必须显式配置源集,否则它会在尝试处理 ModuleInfo 源集时失败。

我终于得到了这个版本的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】:

    这个问题已经有一年多了,但如果有人在这里绊倒,Gradle Modules Plugin 现在支持此功能,因为版本 1.5.0

    使用此插件,您无需创建自定义源集,只需调用modularity.mixedJavaRelease 方法即可。

    这是一个如何将插件应用到一个主 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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-29
      • 1970-01-01
      • 2018-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多