简体   繁体   中英

JDK11 Migration: Compilation error shown in Eclipse 2018-12 but code runs fine

While migrating from Oracle JDK 8 to Open JDK 11.0.1 using Eclipse 2018-12 I obviously found another JPMS-related bug making it hard to work with external non-modularized .jar's within a modular java project. I tracked my problem down to the full example below.

The example was derived from the migration process of a real project (using the still non-modularized javax.servlet.api ) which caused some headaches. It consists of four maven projects M, N, Y and X making up one java module each, and another maven project that makes up a non-modular java project W . I use maven and the maven-compiler-plugin 3.8.0 . My observations are:

  • Eclipse shows errors in M.java but running class M with default options runs without errors
  • if I include the artifact w as additional maven dependency in project M , the errors remain
  • if I rename project Y to project O along with artifact, package name and module-info, no errors are shown
  • if I remove the requires w in module m , no errors are shown
  • if I make project W modular by adding a module-info.java , no errors are shown
  • if I make project W modular by adding Automatic-Module-Name: w in MANIFEST.MF , the error remains

Obviously, re-declaring automated modules like module w in top-level projects seems to cause problems with the built-in Eclipse compiler and does not allow us to work properly with Eclipse (whereas running the project works well). In my opinion, this mismatch is another bug in Eclipse 2018-12 (along with the problems I described in Automatic modules not found in Eclipse 2018-12 when project is opened and Java module not found at runtime even with requires transitive ).

My question is: Can someone confirm this as a bug, or is it already known? For us it is a complete show stopper since our project depends on different libraries that are neither modular nor have they the Automatic-Module-Name attribute. And as long the Eclipse bug described in this post exist we are not be able to migrate further to JDK 11.

Sidemark : We don't want to configure our projects after checking out from SCM to get it running in Eclipse. For us, it was not necessary until now ( and that's actually really great when working with Maven and Eclipse, thanks to everyone who made that possible so far! ), and I hardly try to avoid to manually configure module paths of our eclipse projects or run configurations.


So, here is the complete and reproducable example:

Project M (modular)

// 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>

Project N (modular)

// 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>

Project Y (modular)

// 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 (modular)

// 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 (non-modular)

// 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>

Please do a Maven > Update Projects … > all to get everything in sync after defining the projects or changing your module dependencies. Also, please close also the non-modular project M after doing a mvn clean install since otherwise you would get the error described here: Automatic modules not found in Eclipse 2018-12 when project is opened .

Indeed Eclipse had a bug, which surfaced only when compilation was performed in a very specific order.

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 pov 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.

(Edited:) The bug has been addressed as Eclipse bug 543765 , the fix is available since release 2019-03.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM