javaeclipsegradlejava-platform-module-system

Eclipse Java 17 setup issue related to (Java 9) Module System - The package * is accessible from more than one module: <unnamed>, java.xml


First of all I researched a lot about this issue already and it's is not a duplicate of the numerous and typical "The package * is accessible from more than one module: <unnamed>, java.xml" questions for which the simple answer is: "remove duplicate dependencies from your classpath".

This we already did and for the colleagues using IntelliJ IDE it also is working fine and not bringing up the issues Eclipse does.

I suspect it to be a side-effect of the special setup of the project which Eclipse is not handling well and therefore is leading to the issue. But one after the other:

Issue

In the end it's a "typical" "The package org.w3c.dom is accessible from more than one module: <unnamed>, java.xml" issue. But unlike having defined redundant, conflicting dependencies, it's more due to the special project setup and Eclipse not properly handling the project setup, since the conflicting dependencies both come from the same system library JRE.

From the server module:

Compile errors

Project Background

We are working on the project for a long time now (big legacy project). During the work we've already upgraded from Java 1.6 over Java 1.8 to now Java 17. All the upgrades were fine so far except the last one. But only with the introduction of Java 17 also the new module server-util was introduced, which seems to cause the issues (see below).

When using Java 1.8 in the Compiler-Options the project also is compiling fine, but as soon the Compiler-Options are increased to >Java 9 (e.g. 17) the compile issues occur.

Tools

Project Setup

The project is structured into 4 modules: client, server, share and server-util. Whereby client and server usually are independend modules and the share is shared between the two. server-util is a small utility module which provides additional utilities/ services for the server module. A graphical representation would look like this:

client    server - server-util
    \     /
     share

All of the modules except the server-util module are "simple" Java-Projects (so no Maven or Gradle is in place here (yet)). The build tool used for this modules is Ant. Only the server-util module makes use of Gradle.

Observations/ Issue

  1. When switching the Compiler-Options from 1.8 to 17 as explained above the issues start to occur. Interestingly the issues only arise between the server and server-util modules. client - share and server - share don't show this kind of issues.
  2. When tracing down the conflicting dependencies they both originate from the configured default JRE for the workspace which is a JDK 17 (both server module and server-util use the same). But during the trace once it's opened from server module and once from server-util module (-> in the Package Explorer view). Therefore it seems Eclipse doesn't recognize it's the same JRE/ JDK being used within the projects (whereby it does recognize it between the client - share and server - share modules and therfore doesn't bring up the issues).
  3. Since server-util project is a Gradle project Eclipse offers the Gradle -> Refresh Gradle Project option in the context menu. Usually when I perform this operation this also leads to compile issues, since the usually configured JRE isn't recognized anymore or even actively reset. => When opening the Build Path of the module none of the available JREs is selected/ configured anymore. I always need to manually select "Workspace default JRE" (-> JDK 17) again.

Assumption

Since the setup is working for the colleagues using IntelliJ IDE and also at Build Time (-> Ant) and runtime everything is working fine I don't think it's a general or plain dependency issue.

My assumption is that Eclipse cannot handle the relationship between the server and server-util projects well. And the most obvious reason is that one is a plain, "simple" Java Project, whereby the other is a Gradle project. Therefore Eclipse doesn't seem to properly detect the usage of the same "system library -> JRE" and therefore falsely is claiming the error "The package org.w3c.dom is accessible from more than one module: <unnamed>, java.xml".

But it's not exactly clear if it's the combination of both or maybe even solely related to the Gradle project itself (whether it's our project's setup or some kind of issue with the Eclipse Gradle plugin or so).

I've tried different things like

So none of this helped.

I hope someone may have some experience with this and some other ideas to resolve the issues, even though the setup (plain Java-Project depending on Gradle project) may be quite special.

EDIT:

The dependencies server-util brings (in order of definition)

Implementation scope

Test scope


Solution

  • So apparently during the creation of the minimal reproducible example (MRE) I was able to narrow down the issue and answer my own question - thanks to all the commentators for the support!

    Root cause

    In the end it turned out that the problem was in module server itself and that it was not related to the relationship of the modules server and server-util. Therefore the issue was also not caused by the Gradle nature of the server-util module or Eclipse handling the setup.

    The final root cause was the jaxp-api.jar dependency of the server module itself. It was duplicating the javax.xml namespace/ package of the JRE, which is against the rules of the Java Platform Module System (JPMS) and therefore leading to the compile errors.

    => Contrary to what was assumed at the beginning, it was a typical dependency problem in the end.

    Unfortunately it was masked by several impressions:

    1. Eclipse misleading behaviour by opening the wrong library in the "Package-Explorer" view when looking for the sources of the conflicting libraries/ classes.1
    2. The project setup having been successfully imported by colleagues using IntelliJ IDEA
    3. The project being built properly by the build tools and operating fine in production

    1 This you can do via "Ctrl + Click" -> Open Implementation. But this time Eclipse opened 2x the JRE System Library (1x from server module, 1x from server-util module) instead of 1x the JRE System Library and 1x the conflicting jaxp-api.jar as it used to do. Usually this always was a good and reliable way to identify duplicate/ conflicting libraries in the past.

    How did I find out?

    In order to help others facing this or similar issues, let me explain which steps I performed to identify the root cause.

    The crucial step is to prepare a minimal reproducible example (MRE) in order to view the individual components in isolation and narrow down the problem:

    1. Create a small representative project server-reproduce with just one (simple) class XMLUtils, to reproduce the problem in the simplest form (-> check the bottom for the example code)

    2. Create a small representative project server-util-java as a simple Java project (-> not managed by Gradle) - containing no further dependencies than the workspace default JRE 17 System Library (-> same one as used by the server-reproduce module)

    3. Create a small representative project server-util-gradle as a Gradle project (-> managed by Gradle) - containing no further dependencies than the workspace default JRE 17 System Library (-> same one as used by the server-reproduce module)

    4. Add the server-util-java module as a project dependency to the server-reproduce module

      => Expectation: No issues; Observation: No issues
      
    5. Remove the server-util-java module and add the server-util-gradle module as a project dependency to the server-reproduce module

      => Expectation: Issues will start to occur; Observation: No issues
      

    This shows that the assumption that the problems were caused by Eclipse not being able to handle the combination of a simple Java project referencing a project managed by Gradle, and therefore not being able to properly resolve the JREs used, was not the root cause.

    Further steps to locate the problem:

    1. Remove the server-util-gradle module as a project dependency from the server-reproduce module

    2. Add all the dependencies of the original server module to the newly created server-reproduce module

       => Expectation: No issues; Observation: Issues started to occur
      

    This shows the issue must be solely within the setup/ dependencies of the server-reproduce module and that no other project dependency is involved.

    Finding the dependency causing the error

    Unfortunately the earlier helpful way via "Ctrl + Click" -> Open Implementation, which should show the conflicting library in the "Package-Explorer", didn't work here either. Again Eclipse opened 2x the JRE System Library (but this time the identical one) instead of 1x the JRE System Library and 1x the library causing the error.

    Instead use the "Java-Search" from the Search window (-> Ctrl + H) as follows:

    Eclipse Java Search

    This search now properly displays all dependencies introducing declarations for the conflicting class:

    Java Search showing all conflicting declarations

    And reveals jaxp-api.jar is causing the compile issues.

    * Note: According to my expectation there is a minor bug in the "Java Search" if you're interested about this check out the section "Further reading" below.

    Resolution

    To resolve the compile issues remove the jaxp-api.jar and it's implementation(s) (like jaxp-ri.jar) without replacement (jaxp-ri.jar was not directly leading to compile issues, but also is obsolete with Java 9 and above). As per my research the former jaxp-api.jar, which was distributed in a standalone bundle, has been integrated into the delivery of Java SE and therefore doesn't need a replacement.

    Sources:

    XMLUtils example code

    import org.w3c.dom.Attr;
    import org.w3c.dom.NamedNodeMap;
    import org.w3c.dom.Node;
    
    public class XMLUtils {
    
        private XMLUtils() {
            // do not instantiate
        }
    
        /**
         * Provides the value of the specified attribute - when present. Otherwise null
         */
        public static String getAttributeValue(Node anElement, String attrName) {
            NamedNodeMap nodeMap = anElement.getAttributes();
            for (int i = 0; i < nodeMap.getLength(); i++) {
                Node n = nodeMap.item(i);
                if (attrName.equalsIgnoreCase(n.getNodeName())) {
                    return ((Attr) n).getValue();
                }
            }
            return null;
        }
    }
    

    For the record

    Adding the following configuration line to a project's .settings/org.eclipse.jdt.core.prefs as suggest by the link (https://stackoverflow.com/a/74890645/6505250) provided by howlger in the comments:

    org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage=enabled

    also will resolve the compile issues.

    Just make sure to use a recent version of Eclipse. The configuration shall be supported from Eclipse 2022-12. Therefore setting it on my original Eclipse 2021-06 had no effect, but was working fine with Eclipse 2023-09.

    => It must be highlighted that this is not recommended and rather a workaround! If possible the root cause should properly be fixed by resolving the conflicts in the project setup/ dependencies e.g. as described above.


    Further reading

    Of course the real project's setup was not that simple and kept one more difficulty ready.

    The module server is not only dependent on the module server-util, but server-util also is physically contained in the project folder of the server module as a subfolder.

    It looks like that:

    repository-root/
    ├─ server/
    │  ├─ lib/
    │  │  ├─ main/
    │  │  │  ├─ libraries
    │  ├─ server-util/
    │  │  ├─ lib/
    │  │  │  ├─ main/
    │  │  │  │  ├─ libraries e.g. xml-apis-1.0.b2.jar
    

    * server-util being nested inside of server

    This leads to the fact that if one sets up the project (server) in a new workspace in Eclipse, it recognizes the libraries from server-util and automatically adds them to the server module. If you don't pay attention here it's very hard to recognize!

    Of course this is Eclipse's known default behaviour and usually what one needs, but not for this project. Not paying much attention I overlooked it at first of course.

    Therefore the resolution above was not enough and even though having removed jaxp-api.jar from the build path the compile issues still occurred.

    Luckily by using the "Java Search" (-> Ctrl + H) as explained above I could identify the additional conflicting libraries quickly:

    Conflicting dependencies on real project

    As can be seen above it turned out that also xml-apis-1.0.b2.jar was leading to the compile issues. But this jar anyways was not expected to be on the build path from the beginning. Therefore, it was rather a coincidence that this step has become necessary and should actually not have been the case.

    But this revealed a possible bug in the Eclipse "Java Search" (-> Ctrl + H). As I reproduced the same scenario in my MRE I noticed the "Java Search" is not displaying all (conflicting) dependencies in my MRE projects even though it should. I suspect it's because the dependencies in my MRE were structured slightly differently and located outside of the project folder like the following:

    eclipse-workspace/
    ├─ server-reproduce/
    │  ├─ lib/
    │  │  ├─ main/
    │  │  │  ├─ libraries
    ├─ server-util-gradle/
    │  ├─ lib/
    │  │  ├─ main/
    │  │  │  ├─ libraries e.g. xml-apis-1.0.b2.jar
    

    * server-util-gradle not being nested inside of server-reproduce and residing on the same folder level

    => In this scenario the compile issues still remained (because the server-reproduce referenced the xml-apis-1.0.b2.jar), but the "Java Search" was not displaying it as a source of declaration for the conflicting classes, even though the checkbox "Application libraries" was ticked as displayed at the top. I want to highlight this, in case someone is following the steps described in this answer and may be wondering why not all conflict causing dependencies are displayed within the search.

    => To me it seems like a bug in the search in Eclipse, since in this scenario I definitely would consider xml-apis-1.0.b2.jar to be an "Application library".

    One final question remains though

    Why is xml-apis-1.0.b2.jar leading to the compile issues when being referenced as a direct dependency in server or server-reproduce respectively, but when being pulled as a transitive dependency through server-util (as a Gradle project) it's not?

    => This I still didn't figure out and it surprises me. Anyways it'll be not relevant for the project anymore since I'm planning to also remove xml-apis-1.0.b2.jar entirely. But I'm still curious and would like to know. So if you have an idea feel free to let me know in the comments!