【问题标题】:Gradle build - add module pathGradle build - 添加模块路径
【发布时间】:2020-03-01 15:24:54
【问题描述】:

我的问题:如何为gradle build 设置模块路径?

我已经习惯了从命令行使用 Java 模块。我经常在 Powershell 中进行练习,结果生成了这些源文件。

└───src
    ├───appMod
    │   │   module-info.java
    │   │
    │   └───appPack
    │           Entry.java
    │
    └───greetMod
        │   module-info.java
        │
        └───greetPack
                Hello.java

appMod/模块信息

module appMod {
    requires greetMod;
}

appMod/appPack.Entry

package appPack;

import greetPack.Hello;

public class Entry {
    public static void main(String[] args) {
        System.out.println(new Hello().sayHello());
    }
}

greetMod/模块信息

module greetMod {
    exports greetPack;
}

greetMod/greetPack.Hello

package greetPack;

public class Hello {
    public String sayHello() {
        return "Greetings from Hello class!";
    }
}

由于appMod模块需要greetMod,所以我先编译jargreetMod。

javac -d out/greetMod src/greetMod/module-info.java src/greetMod/greetPack/Hello.java;
jar cf lib/greetJar.jar -C out/greetMod .;

然后我编译并 jar appMod,但在此过程中,我指定了新的 greetMod jar (greetJar) 所在的模块路径 (-p)(在 lib 中)。

javac -d out/appMod -p lib src/appMod/module-info.java src/appMod/appPack/Entry.java;
jar cfe lib/appJar.jar appPack.Entry -C out/appMod .;

然后我可以通过添加模块路径来运行它或部分地链接它。

java -p lib -m appMod;
jlink -p lib --add-modules appMod --launcher launch=appMod --output dist;
dist/bin/launch

我现在想在 Gradle 中做同样的练习,但我不知道如何做相当于设置模块路径的方法,例如 -p lib。我见过sourceSets 的代码,以及dependencies 的无数变体,但到目前为止,我还没有能够组合出一些有用的东西。我还阅读了相互矛盾的声明,它们都说 Gradle doesn't fully support Java modulesGradle does support them

【问题讨论】:

    标签: java gradle command-line dependencies java-module


    【解决方案1】:

    我知道这可能会令人困惑,但绝对可以通过 gradle 来完成。您将需要使用多项目构建来完成这项工作。在您最顶层的build.gradle 中,执行以下操作:

    subprojects {
        apply plugin: 'java'
    
        sourceCompatibility = 1.9
    
        compileJava {
            doFirst {
                options.compilerArgs += [
                        '--module-path', classpath.asPath
                ]
                classpath = files()
            }
        }
    }
    

    在你的settings.gradle:

    rootProject.name = 'module-testing'
    
    include 'src:greetMod'
    include 'src:appMod'
    

    appMod 中的所有内容都应移动到名为appModSrc 的文件夹中。对greetMod 执行相同操作,因此请使用greetModSrc


    greetMod

    目录结构:

    ├── build.gradle
    └── greetModSrc
        ├── greetPack
        │   └── Hello.java
        └── module-info.java
    

    build.gradle

    sourceSets {
        main {
            java {
                srcDirs 'greetModSrc'
            }
        }
    }
    

    appMod

    目录结构:

    ├── appModSrc
    │   ├── appPack
    │   │   └── Entry.java
    │   └── module-info.java
    └── build.gradle
    

    build.gradle

    plugins {
        id 'application'
    }
    
    sourceSets {
        main {
            java {
                srcDirs 'appModSrc'
            }
        }
    }
    
    application {
        mainClassName 'appPack.Entry'
    }
    
    jar {
        doFirst {
            manifest {
                attributes('ModuleMainClass': mainClassName)
            }
        }
    }
    
    dependencies {
        implementation project(':src:greetMod')
    }
    

    使用此设置,您可以简单地运行 ./gradlew :src:appMod:run:

    > Task :src:appMod:run
    Greetings from Hello class!
    

    你可以在这里下载idea项目:https://github.com/MVCE-Superstars/multi-java9-gradle

    【讨论】:

      【解决方案2】:

      由于Gradle 6.4,您可以使用在项目Java插件上设置inferModulePath属性来自动设置模块路径:

      subprojects {
          plugins.withType(JavaPlugin).configureEach {
              java {
                  modularity.inferModulePath = true
                  sourceCompatibility = JavaVersion.VERSION_11
                  targetCompatibility = JavaVersion.VERSION_11
              }
          }
      }
      

      【讨论】:

      • 我在 Gradle 6.6.1 中使用这个,编译工作正常,但没有 META-INF 的东西,ServiceLoader 功能就无法工作。因此它必须仍在使用我假设的类路径。
      • 这也不会将非模块化 jar(名称:'sqlite-jdbc',版本:'3.32.3.2')放入模块路径,使其成为自动模块(正在工作在我之前的 netbeans ant 项目中)=> 这与将所有内容放入模块路径不同
      • @MartinMeeser:很高兴您提供了有关限制的信息。我自己不知道有关此解决方案的任何详细信息。
      【解决方案3】:

      首先请注意:我在使用 Java 15 的 Gradle 6.6.1。

      这是我观察到的:

      1. 为了使编译工作,每个项目都需要:

        java {
            modularity.inferModulePath = true
        }
        
      2. 这可以在rootbuild.gradle通过

         subprojects {
             apply plugin: "java"
             java {
                 modularity.inferModulePath = true
             }
         }
        
      3. 为了使用带有gradle run 的模块路径(ServiceLoader 在没有 META-INF 的情况下工作,反射限制......)您必须使用以下应用程序部分:

        application {
             mainModule = 'org.gradle.sample.app' // name defined in module-info.java
             mainClass = 'org.gradle.sample.Main'
             // DO NOT USE   mainClassName = 'org.gradle.sample.Main'
        }
        

      我花了相当长的时间从几个 Gradle 页面拼凑起来 --- 但都是here

      注意:

      这不会是模块路径的非模块化 jar。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-17
        • 2013-07-21
        • 2020-07-28
        • 2017-05-01
        • 2016-06-03
        • 2022-01-21
        • 1970-01-01
        相关资源
        最近更新 更多