java - JDK11迁移: Compilation error shown in Eclipse 2018-12 but code runs fine

标签 java java-module java-11

使用Eclipse 2018-12Oracle JDK 8迁移到Open JDK 11.0.1时,我显然发现了另一个与JPMS相关的错误在模块化 java 项目中很难使用外部非模块化 .jar。我将问题追溯到下面的完整示例。

这个例子源自一个真实项目的迁移过程(使用仍然非模块化的javax.servlet.api),这引起了一些头痛。它由四个 Maven 项目M、N、Y 和 X 组成,每个项目组成一个 Java 模块,另一个 Maven 项目组成一个非模块化 Java 项目W。我使用 maven 和 maven-compiler-plugin 3.8.0。我的观察是:

  • Eclipse 在 M.java 中显示错误,但使用默认选项运行类 M 运行时没有错误
  • 如果我将工件 w 作为项目 M 中的附加 Maven 依赖项包含在内,错误仍然存​​在
  • 如果我将项目 Y 以及工件、包名称和模块信息重命名为项目 O,则不会显示任何错误
  • 如果我删除模块 m 中的 requires w,则不会显示任何错误
  • 如果我通过添加 module-info.java 使项目W模块化,则不会显示任何错误
  • 如果我通过在 MANIFEST.MF 中添加 Automatic-Module-Name: w 使项目W模块化,错误仍然存​​在

显然,在顶级项目中重新声明像模块w这样的自动化模块似乎会导致内置Eclipse编译器出现问题并且不允许我们工作正确地使用 Eclipse(而运行该项目效果很好)。在我看来,这种不匹配是 Eclipse 2018-12 中的另一个错误(以及我在 Automatic modules not found in Eclipse 2018-12 when project is openedJava module not found at runtime even with requires transitive 中描述的问题)。

我的问题是:有人可以确认这是一个错误吗,还是已经知道了?对我们来说,这完全是一个阻碍,因为我们的项目依赖于不同的库,这些库既不是模块化的,也没有 Automatic-Module-Name 属性。只要本文中描述的 Eclipse 错误存在,我们就无法进一步迁移到 JDK 11。

附注:我们不想在从 SCM checkout 后配置我们的项目以使其在 Eclipse 中运行。对于我们来说,直到现在还没有必要(在使用 Maven 和 Eclipse 时,这实际上非常好,感谢迄今为止使这一切成为可能的每个人!),而且我几乎试图避免手动配置我们的 Eclipse 项目或运行配置的模块路径。

<小时/>

所以,这是完整且可重现的示例:

M 项目(模块化)

// M.java
package m;
import com.example.n.N;
public class M {
    public static void main(String[] args) {
        System.out.println("M");
        N.main(null);
    }
}

// module-info.java
open module m {
    requires n;
    requires w;
}

// pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mavenexample2</groupId>
  <artifactId>m</artifactId>
  <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency> 
          <groupId>com.mavenexample2</groupId>
          <artifactId>n</artifactId>
          <version>0.0.1-SNAPSHOT</version>         
        </dependency>

        <dependency>
          <groupId>com.mavenexample2</groupId>
          <artifactId>y</artifactId>
          <version>0.0.1-SNAPSHOT</version>             
        </dependency>
    </dependencies> 
</project>

N 项目(模块化)

// N.java
package com.example.n;
public class N {
    public static void main(String[] args) { 
        System.out.println("N");
    }
}

// module-info.java
open module n {
    exports com.example.n;
}

// pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mavenexample2</groupId>
  <artifactId>n</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</project>

项目 Y(模块化)

// Y.java
package com.example.y;
public class Y {
    public static void main(String[] args) { 
        System.out.println("Y");
    }
}

// module-info.java
open module com.example.y {
    exports com.example.y;
    requires com.example.x;
}

// pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mavenexample2</groupId>
  <artifactId>y</artifactId>
  <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.mavenexample2</groupId>
            <artifactId>x</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

Project X(模块化)

// X.java
package com.example.x;
public class X {
    public static void main(String[] args) { 
        System.out.println("X");
    }
}

// module-info.java
open module com.example.x {
    exports com.example.x;
    requires w;
}

// pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mavenexample2</groupId>
  <artifactId>x</artifactId>
  <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency> 
          <groupId>com.mavenexample2</groupId>
          <artifactId>w</artifactId>
          <version>0.0.1-SNAPSHOT</version>             
        </dependency>
    </dependencies>

</project>

Project W(非模块化)

// W.java
package external;
public class W {
    public static void main(String[] args) { 
        System.out.println("W");
    }
}

// pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mavenexample2</groupId>
  <artifactId>w</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</project>

请执行Maven >更新项目...>所有操作,以便在定义项目或更改模块依赖项后使所有内容保持同步。另外,请在执行 mvn clean install 后关闭非模块化项目 M,否则您会收到此处描述的错误:Automatic modules not found in Eclipse 2018-12 when project is opened .

最佳答案

事实上,Eclipse 有一个错误,只有当编译以非常特定的顺序执行时才会出现。

Background: In the era of JPMS a package has different content depending on which module is asking. In the example different modules see different configurations for package com.example: from some p.o.v. it contains a child package n in other perspectives it doesn't. For performance sake, each result of such lookup is cached, which caused the order dependence: which module first looked up package com.example decided what contributions to the package were known.

Curiously, the same JPMS that makes split packages illegal, requires a compiler to treat each parent package with multiple contributing modules as a split package, causing a significant increase in implementation complexity.

(已编辑:) 该错误已被解决为 Eclipse bug 543765 ,该修复自 2019-03 版本起可用。

关于java - JDK11迁移: Compilation error shown in Eclipse 2018-12 but code runs fine,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54329075/

相关文章:

java - 如何确保 Spring Security 安全资源服务器仅接受来自自己应用程序的 JWT token

Java 模块化,使用 gradle 的 java9-modularity 插件的测试类中的编译问题

java - JUnit5 Gradle 插件覆盖默认构建任务

java - 在循环中按名称访问变量

java - 在模块路径上运行 OptaPlanner

java - Keycloak java.lang.NoClassDefFoundError : java/security/acl/Group using Springboot

java - 设置最大堆大小是否会影响字符串池大小?

java - 在 module-info.java 中找不到所需的模块

java - Spring Boot 测试加载 ApplicationContext 失败

java - 如何使用 Gradle 设置 JPMS 模块的 ModuleMainClass 属性?