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

一个人想着一个人 提交于 2019-11-26 09:35:52

问题


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.

回答1:


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



回答2:


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.




回答3:


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.




回答4:


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




回答5:


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




回答6:


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>


来源:https://stackoverflow.com/questions/51094274/eclipse-cant-find-xml-related-classes-after-switching-build-path-to-jdk-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!