1

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.

user27772
  • 522
  • 1
  • 4
  • 18
  • Eclipse 2018-12 has a lot bugs ... I prefer with Eclipse 4.7.3 though it doesn't support Java 11. Or just use IDEA. – Eric Jan 23 '19 at 15:55
  • @Eric Wang: Thanks for the suggestion. For Eclipse, I filed a bug report since the problem described would be a show stopper for us when staying with Eclipse: https://bugs.eclipse.org/bugs/show_bug.cgi?id=543765 – user27772 Jan 24 '19 at 08:23
  • So far no bug in Eclipse could be identified. Access to an automatic module *must* be via the jar file. M needs a dependency on w for `requires w` to resolve. With these points observed compilation & running work as designed. – Stephan Herrmann Jan 27 '19 at 17:57
  • @StephanHerrmann: Access to the automatic module w _is_ done via the .jar file if W is installed in .m2 and closed afterwards. M _has_ already an (indirect) dependency on w (M depends on Y depends on X depends on W). In my opinion, both requirements are satisfied but Eclipse still _shows_ error messages in class M (whereas _runs_ this class as expected). Please see my comments in https://bugs.eclipse.org/bugs/show_bug.cgi?id=543765. – user27772 Jan 28 '19 at 11:07
  • After identifying the typo in the steps to reproduce (also visible in this question), an Editor-only error marker can be reproduced. This should not hinder development, but still needs fixing in Eclipse, of course. – Stephan Herrmann Jan 29 '19 at 14:58

1 Answers1

2

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

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

Stephan Herrmann
  • 7,963
  • 2
  • 27
  • 38