包与 Java 9 中的自动模块冲突

随着Java 9的临近,我认为将我的一些项目移植到Java 9上将是一个很好的学习练习。在我的一个项目中,我有rxjava和rxjavafx的依赖关系

dependencies {
    compile 'io.reactivex:rxjava:1.2.6'
    compile 'io.reactivex:rxjavafx:1.0.0'
    ...
}

我想将此项目创建为命名模块。为此,我需要创建一个文件,并且我需要在此处指定和的要求。但是,这些库尚没有任何模块信息。module-info.javarxjavarxjavafx

为了解决这个问题,我已经读到我需要创建自动模块。据我所知,我需要重命名和jars以具有一个简单的名称,然后在参数中列出jar。然后,我使用jar名称在我的中添加一个指令。rxjavarxjavafx--module-pathrequiresmodule-info.java

module com.foo.bar {
    requires rxjavafx;
    requires rxjava;
}

我写了一个 gradle 任务来为我编辑 jar 名称,它似乎在大多数情况下都有效。它采用所有需要编译的 jar,并重命名它们以不包含版本信息或斜杠。然后将这些文件串联成一个单独的字符串::

tasks.withType(JavaCompile) {
    delete { delete '/tmp/gradle' }
    copy {
        from configurations.compile + configurations.testCompile
        into '/tmp/gradle'
        rename '(.*)-[0-9]+\\..*.jar', '$1.jar'
        rename { String fileName -> fileName.replace("-", "") }
    }
    options.compilerArgs += ['--module-path', fileTree(dir: '/tmp/gradle', include: '*.jar').getFiles().join(':')]
}

当然,这些库会共享一些软件包名称...但是,这会导致编译器吐回错误,例如:rx

error: module  reads package rx.subscriptions from both rxjava and rxjavafx
error: module  reads package rx.schedulers from both rxjava and rxjavafx
error: module  reads package rx.observables from both rxjava and rxjavafx
error: module rxjava reads package rx.subscriptions from both rxjavafx and rxjava
error: module rxjava reads package rx.schedulers from both rxjavafx and rxjava
error: module rxjava reads package rx.observables from both rxjavafx and rxjava
error: module rxjavafx reads package rx.subscriptions from both rxjava and rxjavafx
error: module rxjavafx reads package rx.schedulers from both rxjava and rxjavafx
error: module rxjavafx reads package rx.observables from both rxjava and rxjavafx

似乎解决此问题的唯一方法是将内容重新打包到单个jar中,并将其添加为单个模块。不过,这似乎不是一个好的解决方案...rxjavarxjavafx

所以我的问题是:

  • 我是否正确使用了新的模块系统?
  • 对于此错误,我该怎么办?和
  • 这些依赖项是否阻止我更新,或者我应该只等待 rx 更新其库?

注意:我尝试过使用标准java / javac运行它,它们会导致相同的问题。这里也是我的java版本:

java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+140)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+140, mixed mode)

答案 1

我是否正确使用了新的模块系统?

是的。您看到的是预期行为,这是因为JPMS模块不允许拆分包。

如果您不熟悉术语“拆分包”,它本质上意味着来自两个不同模块的同一包的两个成员。

例如:
com.foo.A(来自moduleA.jar)
com.foo.B(来自moduleB.jar)

对于此错误,我该怎么办?

您有两种选择:

  1. (更难)“拆分”包依赖项。但是,如果您不熟悉库的内部工作原理,这可能很困难或不可能
  2. (更容易)将两个罐子组合成一个罐子(因此是一个单一的自动模块),如上所述。我同意这不是一个“好”的解决方案,但是首先拆分包通常也不是一个好主意。

这些依赖项是否阻止我更新,或者我应该只等待 rx 更新其库?

希望rx最终会更新他们的库,以便在将来的某个时候没有拆分包。在那之前,我的建议是将两个罐子一起砸成一个罐子(选项#2)。


答案 2

我有类似的问题:

error: module flyway.core reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
error: module slf4j.api reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
error: module hibernate.core reads package javax.transaction.xa from both jboss.transaction.api.1.2.spec and java.sql
.../src/main/java/module-info.java:1: error: module eu.com.x reads package javax.transaction.xa from both java.sql and jboss.transaction.api.1.2.spec

我可以通过检查我的项目传递依赖项(“gradle依赖项”或“mvn依赖项:tree”可能会有所帮助)并通过代码类似于以下内容来消除拆分包编译问题:

configurations.all {
    exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
}

<dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.10.Final</version>
      <exclusions>
        <exclusion>
          <groupId>org.jboss.spec.javax.transaction</groupId>
          <artifactId>jboss-transaction-api_1.2_spec</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>

没有罐子重新包装,我的问题。#JDK8上未出现此问题。排除依赖项可能并非在每个项目中都有帮助。


推荐