Eclipse can't find XML related classes after switching build path to JDK 10
Asked Answered
S

10

83

I'm developing on a Maven project (branch platform-bom_brussels-sr7) in Eclipse. When I recently tried switching the Java Build Path for the project to JDK 10, Eclipse build can no longer find classes such as javax.xml.xpath.XPath, org.w3c.dom.Document, or org.xml.sax.SAXException. It seems only XML related classes are impacted, mostly from the Maven dependency xml-apis-1.4.01.

Trying a Maven build from Eclipse works without errors. Ctrl-LeftClick on one of the supposedly missing classes finds the class and opens it in the Eclipse editor. It seems only the Eclipse build is impacted.

I tried several things, but none helped. I tried:

  • Project Clean
  • Different Eclipse Versions: Oxygen and Photon.
  • Running Eclipse itself with JDK 8 and JDK 10.
  • Changing Compiler Compliance level for the project. It builds with compliance level 8 and 10 under JDK 8 build path and fails for both with JDK 10 in build path.
Soupspoon answered 29/6, 2018 at 4:24 Comment(8)
I don't know anything about Eclipse but the classes you list are in the java.xml module. If you were previously deploying xml-apis-1.4.01 on the class path then I assume the classes were never actually loaded from that JAR file, they were loaded (and continue to be loaded) from the JDK. Does your project build/run outside of Eclipse?Econometrics
Yes, a maven command line build, or even a explicit maven build within Eclipse both work. It's just the Eclipse built-in build that fails.Soupspoon
You have to use Oxygen.1a or newer, the original Oxygen release simply doesn't support Jigsaw. Your best bet is to stay on Photon while you try to figure this out. As a Maven project, shouldn't you be setting compiler versions in the pom.xml?Kaufman
@Kaufman pom.xml sets the compiier to 10, but you can overwrite this in the Eclipse build preferences.Soupspoon
@AlanBateman are you aware of any excuse why javac would be allowed to accept a package that is not uniquely visible? (see also my answer). I could not find anything that would define named vs. unnamed module conflicts as being exempted from the rule. Am I missing s.t.?Benedic
Stephan - can you bring your question to to jigsaw-dev?Econometrics
@AlanBateman, done, see mail.openjdk.java.net/pipermail/jigsaw-dev/2018-December/… (I didn't see your reply earlier since you didn't "mention" me).Benedic
I am having same issue in 2021, Eclipse 2021-03, OpenJDK 11 and Oracle JDK11. I read below answer and it is great answer but I dont know how to fix it, specifically refering to Solution #3 provided by @StephanHerrmann. The answer is great but I wish there were more details, I was not able to follow with my version of Eclipse.Callery
B
119

I assume that the project being migrated from Java 1.8 still has no module-info.java. This implies you are compiling code in the "unnamed module".

Code in the unnamed module "reads" all observable named and unnamed modules, in particular it reads module "java.xml" from the JRE System Library. This module exports package like java.xml.xpath.

Additionally, you have xml-apis.java on the classpath, which contributes another set of packages of the same names (java.xml.xpath and friends). These are said to be associated to the unnamed module, like your own code.

This situation violates the requirement of "unique visibility" as defined in JLS §7.4.3 (last paragraph). In particular every qualified type name Q.Id (JSL §6.5.5.2) requires that its prefix Q is a uniquely visible package (I'm disregarding the case of nested types for simplicity). Ergo: the program is illegal and must be rejected by compilers.

This leaves us with one question and two solutions:

(1) Question: Why is javac accepting the program?

(2) Solution: If you add module-info.java to your project, you can control via requires which module your project reads, either requires java.xml; or requires xml.apis; (where "xml.apis" is the automatic module name of "xml-apis-1.4.01.jar).

(3) Solution: Short of turning your project into a module, you can still avoid the conflict by excluding java.xml from the set of observable modules. On the command line this would be done using --limit-modules. The equivalent in Eclipse is the "Modularity Details" dialog, see also the JDT 4.8 New&Noteworthy (look for Contents tab). Since java.xml is implicitly required via a lot of other default-observable modules, it may be a good idea to push everything except for java.base from right ("Explicitly included modules") to left ("Available modules") (and selectively re-add those modules that your project needs).

PS: Eclipse still doesn't provide an ideal error message, instead of "cannot be resolved" it should actually say: "The package javax.xml.xpath is accessible from more than one module: javax.xml, <unnamed>.

PPS: Also weird: how come that changing the order between JRE and a jar on the classpath (such ordering is not a concept supported by javac nor JEP 261) changes the behavior of the compiler.

EDITs:

  • Alex Buckley confirmed that the given situation is illegal, despite what javac says. Bug against javac has been raised as JDK-8215739. This bug has been acknowledged months before the release of Java 12. As of 2019-06 it has been decided that also Java 13 will ship without a fix. Similarly for Java 14. The bug was temporarily scheduled for Java 15, but this plan has been dropped on 2020-04-20.
  • Eclipse error message has been improved to mention the real problem.
  • In Eclipse 2019-06 the UI used for Solution (3) has been revamped. Up-to-date documentation can be found in the online help.
  • As of 2022-12 there's yet another perspective on this issue as described in my other answer. It doesn't invalidate what's said here, but let's things appear in a different light.
Benedic answered 18/12, 2018 at 0:1 Comment(19)
Maybe I'm missing something, but 1) the test project I mentioned in Bug 536928 is using the classpath, not modules, so I had understood (perhaps incorrectly) that module-info.java would have no relevance in a case like this; and 2) to my knowledge the test case I provided does not have xml-apis anywhere in the classpath, nor in transitive dependencies—unless I missed them somewhere.Luxate
@GarretWilson ad (1): since Java 9, the JRE is always modular, so the "old world" is only approximately emulated by putting all non-modular code into one or more unnamed modules. Even for unnamed modules, new rules are in effecte starting with Java 9. Adding module-info.java is not part of the problem, but part of the solution (thereby moving your code from classpath to modulepath).Benedic
@GarretWilson ad (2): different people have dropped different examples into the Eclipse bug report. The initial report had xml-apis.jar in its transitive dependencies, so that's the case being handled in that bug, and it's also the case discussed in this SO thread. If you are certain that xml-apis.jar is nowhere in the picture in your case, then you are facing a different problem - which matches to the observation that only in your case explicit vs. on-demand imports seemed to make a difference, not here, though.Benedic
OK; that's why I put up a bounty, to get to the bottom of it. ;) Thanks for all your hard work. I'm just looking for an answer that applies to my case as well.Luxate
this bounty is expiring so I need to assign it. You gave a really good, comprehensive answer directly related to the original question, so I think it's only right that I assign you the bounty. Unfortunately it looks like my question, which initially appeared to be the same problem, won't be solved by your answer even though solving my problem was my motivation for putting up the bounty. So please don't lower the priority of the Bug 542896 you opened. Thank you!Luxate
This problem affects VS Code with Java 11 too. It shows the new message (The package javax.xml is accessible from more than one module: <unnamed>, java.xml), but I still don't know how to solve it in VS Code. The project builds fine in Maven.Sunward
@Sunward if it's indeed the same issue, then your module dependencies are illegal and need to be fixed. Maven building fine would then simply reflect that you are using a compiler (javac) that still doesn't report this mandatory error (or perhaps maven invokes the compiler with different options than what you have configured in Eclipse).Benedic
Thanks, I guess I will need to exclude some transitive dependencies then (or update more libraries).Sunward
@StephanHerrmann OK, I excluded xml-apis, but some errors persist. What if the dependencies come from something like javax:javaee-api:8.0 or javax.xml.bind:jaxb-api:2.3.0? I thought they were the right and most up to date dependencies to add when you need this Java EE features in Java 11 (if a new question would be better, feel free to tell me so).Sunward
@Sunward Sorry, I'm not really in the position to give recommendations for your project structure. The current thread here only deals with the question, whether or not it is correct to flag that situation as illegal, and we conclude, yes it is correct. From here, Eclipse is only the messenger. Some options that I know of, are: (consistently!) exclude "normal" dependencies or use --limit-modules. If this doesn't suffice and if there isn't yet a thread on strategies regarding xml-apis then, yes, a new question seeking recommendations could be a good idea.Benedic
Great answer. Would you consider writing a follow-up explaining the specific procedure to be followed, using the new UI, for someone that does not understand the precise rules of modular compilation? (I am thinking of students of mine learning Java, I can’t teach them all the complexity of Java in one go but still would like to expose them to interesting projects as soon as possible, where they might face this difficulty.)Lumpfish
@OlivierCailloux I proposed a conference presentation on the general topic as eclipsecon.org/europe2019/sessions/tweak-your-modules When the proposal is accepted and slides are prepared I will put them online (unless I forget ;X).Benedic
@OlivierCailloux Buried in the Eclipse bug report thread at comment 51 are these short instructions that worked for me: "To exclude xml-apis.jar, open your POM in eclipse, go to the Dependency Hierarchy tab, filter by xml-api, right-click on any instance of xml-apis that appears, and choose Exclude Maven Artifact."Cuddy
Third solution: exclude xml.apis from the project dependencies. Drawbacks compared to excluding java.xml from the set of observable modules: 1) the dependency that introduced xml.apis as a transitive dependency (xerces, in my case) might work well with that specific version and misbehave with the one provided with the JRE (which might be older); 2) xml.apis might provide classes not included in the version provided with the JRE. But, similar risks exist with excluding the java.xml module (on which other components might depend). @StephanHerrmann: any thoughts?Lumpfish
Plus, xml.apis:xml.apis:1.4.01 seems to be a subset of java.xml (as provided in OpenJDK 11): I found no class included in the former missing in the latter, except for org.apache.xmlcommons.Version, but conversely, many classes from java.xml are not in xml.apis. Thus I’d rather recommend to exclude xml.apis and keep the JRE module.Lumpfish
My DUMB workaround: Set project compiler as Java 1.8 and rebuild. We don't need any feature later than Java 8 so it's ok for now.Buchan
Is the answer still valid? I don't find this contents tab or details dialog in the latest version of Eclipse. Am I just missing it?Ecphonesis
@Ecphonesis if you're looking for "Modularity Details" mentioned in Solution (3), just read down in the answer, upto the last bullet under "Edits".Benedic
@StephanHerrmann Thanks a lot!Ecphonesis
B
14

While the accepted answer (by myself) is still correct, a further twist of the story was recently brought to my attention:

The original intention may have been to actually support the situation at hand.

See this quote in the original design document "The State of the Module System" (SotMS):

If a package is defined in both a named module and the unnamed module then the package in the unnamed module is ignored.

That document is dated 2016/3/8 08:18, and already at that time was marked "This document is slightly out of date". Moreover, it is not legally binding for any implementation. Still that document has some relevance since what's quoted above is precisely what javac appears to implement (and still implements many years after JDK-8215739 was filed).

IOW, the conflict is not so much a conflict between 1st and 2nd implementation, but a conflict even within Oracle, so it seems. 2 Votes for supporting the situation (SotMS and javac) and only one vote for disallowing (JLS).

Since Eclipse committers are not inclined to resolve this conflict within Oracle, the recent 2022-12 release of Eclipse has a new compiler option: by adding the following line to a project's .settings/org.eclipse.jdt.core.prefs, a user may opt to ignore JLS in this regard:

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

This option puts the decision into the user's hands: do they want JLS-semantics or SotMS/javac semantics (in this particular issue)? Still we were not quite ready to provide a UI option for it, to avoid that users made this choice thoughtlessly, without the background information as provided here.

Personally, I'm not particularly happy about this situation, as it aggravates the fact that Java is not one, but several languages.

Benedic answered 22/12, 2022 at 15:30 Comment(7)
worked for me with lowercase 'enabled'Prothonotary
Thanks, @Mike, I had taken the spelling of an internal constant instead of its value :) - corrected.Benedic
@StephanHerrmann, can this option be set any other way than in an Eclipse project preferences file? Think batch compiler (ECJ, AspectJ compiler). I need to configure this for IntelliJ IDEA and AJC, not for Eclipse IDE and ECJ (JDT Core).Conditioning
@Conditioning can you directly pass this option into the compiler: github.com/eclipse-jdt/eclipse.jdt.core/commit/… ?Benedic
@StephanHerrmann: I had found that piece of code already. But it seems that my question is more basic: How do I pass the option into the compiler directly? What is the CLI syntax for it? Something like passing system properties to the JVM via -DmyProperty=abc? So far, I only managed to pass it in via config file. It does not seem to do what I want, but at least the option is recognised that way.Conditioning
@Conditioning I gave that hint under the assumption that you are invoking the compiler from within Java, with no need for a detour via CLI. Using a property file might be the next best strategy. In that case it would be interesting to know in which way that fails. Feel free to open a GH issue and mention me on it.Benedic
No, I am not calling it from Java but from an IDE (IntelliJ) or from Maven. The funny thing is that the Maven build worked while the IntelliJ build did not, hence I started searching for the compilation errors I saw and found this setting. At this point, I admit that I am stupid and ugly, because the reason the setting did not work at first was sitting in front of the computer. AJC relocates the prefix JavaCore.PLUGIN_ID from "org.eclipse.jdt.core" to "org.aspectj.org.eclipse.jdt.core", which I forgot, because I looked up the setting in the upstream source code, not in the AspectJ fork.Conditioning
W
13

In my case the problem was that xercesImpl : 2.10.0 was a (transient) dependency. This jar bundles org.w3c.dom.html.HTMLDOMImplementation.

As far as I understand the org.w3c.dom package then becomes available from two modules, causing the build to fail. In case one of the dependencies (direct or transient) has classes in one of the 25 packages exported by the java.xml module your build will fail.

Excluding xercesImpl (and also the offenders listed below) in Maven solved the issue for me:

    <dependency>
        <groupId>xyz</groupId>
        <artifactId>xyz</artifactId>
        <version>1.0</version>
        <exclusions>
            <exclusion>
                <groupId>xerces</groupId>
                <artifactId>xercesImpl</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
            <exclusion>
                ...
            </exclusion>
        </exclusions>
    </dependency>

Thanks to Rune Flobakk for giving the hint here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=536928#c73

Other offenders:

  • batik-ext : 1.9 (bundles org.w3c.dom.Window)
  • xom : 1.2.5 (bundles org.w3c.dom.UserDataHandler)
  • stax-api : 1.0.2 (bundles javax.xml.stream.EventFilter)
  • xml-apis : 1.4.01 (bundles org.w3c.dom.Document)
  • xml-beans : 2.3.0 (bundles org.w3c.dom.TypeInfo)
Weightless answered 15/1, 2020 at 15:27 Comment(0)
L
5

This seems to have been reported as Eclipse Bug 536928. Maybe if everyone were to go vote on it it would get them to raise the priority.

Luxate answered 10/12, 2018 at 18:35 Comment(2)
unfortunately with the new eclipse version 2019-06, it is not possible anymore to change the order to resolve the issueAntipodal
fixedProthonotary
E
5

What happens here is you have a wildcard import like import org.w3c.dom.*, stating you want to import all classes from package org.w3c.dom. Now, if there's at least one class in org.w3c.dom provided by a second source, Java must not start (as pointed out here).

(By the way, the message "... cannot be resolved" is replaced by a more accurate error message "The package org.w3c.dom is accessible from more than one module: <unnamed>, java.xml" in more recent Eclipse versions, see this merged change request by Stephan Herrmann.)

To resolve this problem

  1. Open the "Open Type" dialog (Ctrl+Shift+T).
  2. Enter the complete import, so org.w3c.dom.* or org.w3c.dom..
  3. Check the entire list for multiple sources. All entries here should contain only something like "jdk-11-...".
  4. Gather all JARs that contain classes you have multiple sources for.
  5. Open the "Dependency Hirarchy" tab from pom.xml.
  6. Search for the JAR file.
  7. Add an exlusion (right click or edit the pom.xml manually).

Example

I had this findbugs dependency in my pom.xml:

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>findbugs</artifactId>
    <version>${findbugs.version}</version>
</dependency>

Findbugs has two dependencies that need to be excluded:

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>findbugs</artifactId>
    <version>${findbugs.version}</version>
    <exclusion>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
    </exclusion>
    <exclusion>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
    </exclusion>
</dependency>
Edita answered 18/11, 2019 at 17:13 Comment(2)
This worked for me. Moving to Java11 and a dependency from another dependency created the conflict. Once excluded in the POM then it just uses the dependency provided by Java. Mine was javax.xml.namespace.QName <exclusions> <exclusion> <groupId>weblogic</groupId> <artifactId>wlfullclient</artifactId> </exclusion> </exclusions>Levan
I have tried many solutions, only this one worked for me.Multitude
E
5

While Stephan Herrmann's answer is the correct one, I'll post my error and how I got it solved if it can help others. I had the error The package javax.xml.namespace is accessible from more than one module: <unnamed>, java.xml and after inspecting the class with the error, it was the javax.xml.namespace.QName import that was complaining. With the "Open Type" dialog, I found out that it was pulled from stax-api through eureka client. This solved it for me :

<exclusion>
   <groupId>stax</groupId>
   <artifactId>stax-api</artifactId>
</exclusion>
Enteritis answered 12/6, 2020 at 12:50 Comment(3)
"Open Type" was the key to fixing my problem. Thank you!Circumfluent
In my case it was xpp3 which came in via axon-messaging. Excluding xpp3 fixed it.Circumfluent
Thanks for this clue. I was having trouble identifying where the conflicting reference was coming from for org.w3c.dom.Document. Found it easily in Eclipse 2020-12 this way: Selected org.w3c.dom.Document within the import statement that Eclipse flagged, right-click and choose Open Type Hierarchy, in the Type Hierarchy dialog right click Document at the top and choose Implementors > Workspace to reveal all the JARs in all projects in the workspace which are bringing in org.w3c.dom.Document (or whatever type you have selected that is accessible from more than one moduleRascal
P
4

Have seen something very similar under Eclipse 4.8.0 and JDK 10. E.g.

import org.w3c.dom.Element;

was failing to compile in Eclipse with: The import org.w3c.dom.Element cannot be resolved

Even so, pressing F3 (Open Declaration) on that import, Eclipse was able to open the interface definition - in this case under xml-apis-1.4.01.jar.

Meanwhile, builds from Maven direct were working fine.

In this case the fix was to remove this dependency from the pom.xml:

    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.4.01</version>
    </dependency>

Then the compile errors in Eclipse melted away. Following F3 again showed the Element interface - now under the java.xml module, under the JRE System Library under the project. Also the Maven build remained fine.

This feels like a problem with Eclipse resolving a class that it finds in both a JDK module and dependent .jar file.

Interestingly, in a separate environment, this time under Eclipse 4.9.0 and JDK 11, all is fine, with or without the xml-apis:1.4.01 dependency.

Puryear answered 11/12, 2018 at 21:20 Comment(8)
Try cloning and building bitbucket.org/globalmentor/guise/commits/… . Note that I'm using Eclipse Enterprise 2018-12 M3 with the latest updates.Luxate
Managed to get that to build under Eclipse 4.9.0 + JDK 10. Clearly the problem there wasn't the xml-apis dependency, but found such as import org.w3c.dom.*; was still failing. Don't know if it's an option, but breaking these down to type level imports worked around the problem. Example updated version here . The imports were fixed up using Eclipse's Organize Imports, so it looks like quite a lot of change. Happy to make that a proper answer if it works out for you.Puryear
... meant to say, the initial import of the projects wasn't good - NullPointerExceptions in the compiler. But after a Maven/Update Project on the projects, it compiled cleanly.Puryear
But what about 2018-12 M3? I'm not going back to 4.9.0. I'm going forward with Java 11. I can't downgrade Eclipse!Luxate
Fine under 2018-12 RC1 + JDK 11 - the NullPointerExceptions were gone tooPuryear
So you're saying that removing wildcard imports will work around the problem? And is that only for the XML-related imports, or do I have to do it for all imports? And do I have to do it for all files, or just the files that have XML-related imports?Luxate
That's right. I think it may be any JDK level wildcard imports - e.g. import java.net.* was also a problem. Or maybe Eclipse has a problem with wildcard imports against modules in general. It affected 6 files in the source you referenced - changeset herePuryear
Just want to mention for anybody that encounters this issue that xercesImpl:2.12.0 also includes the org.w3c.dom.html package and could also very well be causing similar issues.Coral
L
3

This is more of a work-around, but from my experience it can be resolved by going to the "Java Build Path", the "Order and Export" tab, and sending the "Maven Dependencies" to the bottom (so it's below the "JRE System Library").

Loireatlantique answered 10/12, 2018 at 19:25 Comment(2)
Thanks, I'll try that, but that's not really a workable solution for constant development, as we keep adding submodules and refreshing the Maven configuration, etc.Luxate
Unfortunately even this workaround didn't work for me.Luxate
L
2

Thanks for this clue. I was having trouble identifying where the conflicting reference was coming from for org.w3c.dom.Document. Found it easily in Eclipse 2020-12 this way: Selected org.w3c.dom.Document within the import statement that Eclipse flagged, right-click and choose Open Type Hierarchy, in the Type Hierarchy dialog right click Document at the top and choose Implementors > Workspace to reveal all the JARs in all projects in the workspace which are bringing in org.w3c.dom.Document (or whatever type you have selected that is accessible from more than one module – MikeOnline yesterday

following the directions above from one of the earlier posts helped us solve our issue. what we did was replace Document with GenericDocument and Element with GenericElement from batik - and compile errors are gone - now we just have to test to make sure the implementation matches what we had under java 8. Thanks MikeOnline

Libau answered 26/2, 2021 at 21:48 Comment(0)
H
0

jdk 9+ brought in changes related to project jigsaw. JDK was broken down into various modules and some modules, javaee, jaxb and xml related, are no more loaded by default. You should add these to your maven build directly, instead of expecting them to be in jre classpath. see this SO question

Higdon answered 29/6, 2018 at 4:56 Comment(5)
Thanks for your answer. I don't think the classes in question are part of the ones that are referred to in the other SO question. My problem classes all come from the maven dependency xml-apis-1.4.01. The dependency (as all other maven dependencies) is part of the build path.Soupspoon
Which in the end does not change a thing you have to define a module-info.java definition file see oracle.com/corporate/features/understanding-java-9-modules.html otherwise it will not work.Crawley
Thanks for your comment. I'm not sure this is right though. In the Eclipse path the maven dependency is in the CLASSPATH not in the MODULEPATH, so shouldn't it be treated like a non-module jar? Also why does it only affect this one jar out of many, many similar maven dependencies. Lastly why would only the Eclipse internal build report an error, while both command line maven and explicit maven build in Eclipse succeed?Soupspoon
I'm having the same problem. I can successfully compile my project with javac, but Eclipse can't find these classes. Did you find a solution to this problem?Bibby
I marked this answer down because I don't see how it relates at all. This is a classpath issue, not a module issue. Moreover it works with Maven+JDK on the command line. If it works with Maven+JDK but not in Eclipse, the problem is in Eclipse, and all the prose about how JDK was broken down into modules is ancillary and, while interesting and not necessarily incorrect, is nevertheless irrelevant.Luxate

© 2022 - 2024 — McMap. All rights reserved.