将构建路径切换到 JDK 10 后,Eclipse 找不到 XML 相关的 类

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

我正在 Eclipse 中开发 Maven project(分支 platform-bom_brussels-sr7)。当我最近尝试将项目的 Java Build Path 切换到 JDK 10 时,Eclipse build 再也找不到 classes such as javax.xml.xpath.XPath, org.w3c.dom.Document,或 org.xml.sax.SAXException。似乎只有 XML 相关的 classes 受到影响,主要来自 Maven 依赖项 xml-apis-1.4.01.

尝试从 Eclipse 构建 Maven 没有错误。按住 Ctrl-左键单击其中一个据称缺失的 classes 会找到 class 并在 Eclipse 编辑器中将其打开。似乎只有 Eclipse 构建受到影响。

我尝试了几件事,但 none 有所帮助。我试过了:

jdk 9+ 带来了与拼图项目相关的变化。 JDK 被分解成各种模块,一些模块,javaee,jaxb 和 xml 相关,默认情况下不再加载。您应该将它们直接添加到您的 Maven 构建中,而不是期望它们位于 jre 类路径中。看到这个

这似乎被报告为 Eclipse Bug 536928。也许如果每个人都去投票,他们会提高优先级。

这更像是一种解决方法,但根据我的经验,可以通过转到 "Java Build Path"、"Order and Export" 选项卡并将 "Maven Dependencies" 发送到底部(所以它在 "JRE System Library" 下方)。

在 Eclipse 4.8.0 和 JDK 10 下看到了非常相似的东西。例如

import org.w3c.dom.Element;

无法在 Eclipse 中编译:The import org.w3c.dom.Element cannot be resolved

即便如此,在该导入上按 F3(打开声明),Eclipse 仍能够打开接口定义 - 在本例中为 xml-apis-1.4.01.jar.

与此同时,直接从 Maven 构建工作正常。

在这种情况下,修复是从 pom.xml:

中删除此依赖项
    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.4.01</version>
    </dependency>

然后 Eclipse 中的编译错误消失了。按照F3再次显示Element界面——现在在java.xml模块下,在项目下的JRE系统库下。 Maven 构建也保持良好。

这感觉像是 Eclipse 解决它在 JDK 模块和相关 .jar 文件中发现的 class 的问题。

有趣的是,在单独的环境中,这次在 Eclipse 4.9.0 和 JDK 11 下,一切都很好,有或没有 xml-apis:1.4.01 依赖项。

我假设正在从Java 1.8 迁移的项目仍然没有module-info.java。这意味着您正在 "unnamed module".

中编译代码

未命名模块中的代码 "reads" 所有可观察的命名和未命名模块,特别是它从 JRE 系统库中读取模块 "java.xml"。此模块导出包,如 java.xml.xpath.

此外,您在类路径上有 xml-apis.java,它提供了另一组同名包(java.xml.xpath 和朋友)。这些据说与未命名模块相关联,就像您自己的代码一样。

这种情况违反了"unique visibility"中定义的要求JLS §7.4.3 (last paragraph). In particular every qualified type name Q.Id (JSL §6.5.5.2)要求其前缀Q是唯一可见的包(我无视为简单起见,嵌套类型的情况)。因此:该程序是非法的,必须被编译器拒绝。

这留给我们一个问题和两个解决方案:

(1)问题:javac为什么接受程序?

(2)解决方案:如果你在项目中添加module-info.java,你可以通过requires来控制你的项目读取哪个模块,requires java.xml;或者requires xml.apis;(其中 "xml.apis" 是“xml-apis-1.4.01.jar”的自动模块名称)。

(3) 解决方案:如果不将您的项目转换为模块,您仍然可以通过从可观察模块集中排除 java.xml 来避免冲突。在命令行上,这将使用 --limit-modules 完成。 Eclipse 中的等效项是 "Modularity Details" dialog, see also the JDT 4.8 New&Noteworthy(查找 Contents 选项卡)。由于 java.xml 是通过许多其他默认可观察模块隐式需要的,因此将 java.base 以外的所有内容从右 ("Explicitly included modules") 推到左 ([=70) 可能是个好主意=])(并有选择地重新添加项目需要的那些模块)。

PS:Eclipse 仍然没有提供理想的错误消息,而不是 "cannot be resolved" 它实际上应该说:“包 javax.xml.xpath 可以从多个模块访问: javax.xml、<未命名>。

PPS:也很奇怪:为什么更改类路径上 JRE 和 jar 之间的顺序(这种顺序不是 javac 或 JEP 261 支持的概念)会改变编译器的行为。

编辑:

  • 亚历克斯·巴克利 confirmed that the given situation is illegal, despite what javac says. Bug against javac has been raised as JDK-8215739。此错误已在 Java 12 发布前几个月得到确认。截至 2019 年 6 月,已决定 Java 13 也将在没有修复的情况下发布。 Java 14 也是如此。该错误暂时安排在 Java 15,但该计划已于 2020-04-20 取消。
  • Eclipse 报错信息has been improved提一下真正的问题。
  • 在 Eclipse 2019-06 中,用于解决方案 (3) 的 UI 已 revamped. Up-to-date documentation can be found in the online help

这里发生了什么 你有一个像 import org.w3c.dom.* 这样的通配符导入,说明你想从包 org.w3c.dom 导入所有 classes .现在,如果第二个来源提供的 org.w3c.dom 中至少有一个 class,则 Java 不能启动(正如 所指出的)。

(顺便说一下,消息“...无法解析”被更准确的错误消息“The package org.w3c.dom 可从多个模块访问:, java.xml" 在较新的 Eclipse 版本中,请参阅 Stephan Herrmann 合并的 change request。)

解决这个问题

  1. 打开"Open Type"对话框(Ctrl+Shift+T) .
  2. 输入完成导入,所以org.w3c.dom.*org.w3c.dom..
  3. 检查整个列表是否有多个来源。此处的所有条目应仅包含类似 "jdk-11-...".
  4. 的内容
  5. 收集所有包含 class您有多个来源的 JAR。
  6. pom.xml 打开 "Dependency Hirarchy" 选项卡。
  7. 搜索 JAR 文件。
  8. 添加排除项(右键单击或手动编辑 pom.xml)。

例子

我的 pom.xml:

中有这个 findbugs 依赖项
<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>findbugs</artifactId>
    <version>${findbugs.version}</version>
</dependency>

Findbugs 有两个需要排除的依赖项:

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

在我的例子中,问题是 xercesImpl : 2.10.0 是一个(暂时的)依赖。这个 jar 包 org.w3c.dom.html.HTMLDOMImplementation.

据我了解,org.w3c.dom 包随后可从两个模块获得,导致构建失败。 如果其中一个依赖项(直接或瞬态)在 java.xml module 导出的 25 个包之一中具有 类,您的构建将失败。

在 Maven 中排除 xercesImpl(以及下面列出的违规者)为我解决了这个问题:

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

感谢 Rune Flobakk 在这里给出提示:https://bugs.eclipse.org/bugs/show_bug.cgi?id=536928#c73

其他违规者:

  • batik-ext : 1.9(捆绑组织。w3c.dom.Window)
  • xom : 1.2.5(捆绑组织。w3c.dom.UserDataHandler)
  • stax-api : 1.0.2(捆绑包 javax.xml.stream.EventFilter)
  • xml-apis : 1.4.01(捆绑组织。w3c.dom.Document)
  • xml-beans : 2.3.0(捆绑组织。w3c.dom.TypeInfo)

虽然 Stephan Herrmann 的回答是正确的,但我会 post 我的错误以及我是如何解决它的,如果它可以帮助其他人的话。我有错误 The package javax.xml.namespace is accessible from more than one module: <unnamed>, java.xml 并且在检查 class 错误之后,是 javax.xml.namespace.QName 导入在抱怨。通过 "Open Type" 对话框,我发现它是通过 eureka 客户端从 stax-api 中拉取的。这为我解决了:

<exclusion>
   <groupId>stax</groupId>
   <artifactId>stax-api</artifactId>
</exclusion>

感谢您提供这条线索。我无法确定 org.w3c.dom.Document 的冲突引用来自何处。通过这种方式在 Eclipse 2020-12 中轻松找到它:在 Eclipse 标记的导入语句中选择 org.w3c.dom.Document,右键单击并选择 Open Type Hierarchy,在 Type Hierarchy 对话框中右键单击顶部的 Document 并选择 Implementors > 工作区显示工作区中所有项目中的所有 JAR,这些 JAR 正在引入 org.w3c.dom.Document(或您选择的可从多个模块访问的任何类型 – MikeOnline 昨天

按照前面一篇帖子中的上述说明帮助我们解决了问题。 我们所做的是将 Document 替换为 GenericDocument 并将 Element 替换为 batik 中的 GenericElement - 编译错误消失了 - 现在我们只需要测试以确保实现与我们在 java 下的内容相匹配 8. 谢谢 MikeOnline