在将构建路径切换到 JDK10之后,Eclipse 无法找到与 XML 相关的类

我正在 Eclipse 中的一个 Maven 项目(分支平台-bom _ bussel-sr7)上进行开发。当我最近尝试将该项目的 Java Build Path 切换到 JDK 10时,Eclipse Build 不再能够找到诸如 javax.xml.xpath.XPathorg.w3c.dom.Documentorg.xml.sax.SAXException之类的类。似乎只有与 XML 相关的类受到影响,主要来自 Maven 依赖关系 xml-apis-1.4.01

从 Eclipse 尝试 Maven 构建没有错误。Ctrl-LeftClick 在一个假定丢失的类上找到该类并在 Eclipse 编辑器中打开它。似乎只有 Eclipse 构建受到了影响。

我试了几种方法,但都没有用。我试了:

  • 清洁工程
  • 不同的日食版本: 氧和光子。
  • 使用 JDK8和 JDK10运行 Eclipse 本身。
  • 更改项目的编译器遵从级别。它在 JDK 8构建路径下构建遵从级别8和10,而在构建路径中的 JDK 10都失败了。
60165 次浏览

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

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

这是一个解决方案,但是根据我的经验,它可以通过“ Java 构建路径”,“订单和导出”选项卡,并发送“ Maven 依赖项”到底部(所以它在“ JRE 系统库”的下面)来解决。

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

import org.w3c.dom.Element;

在 Eclipse 中使用 The import org.w3c.dom.Element cannot be resolved编译失败

即便如此,在该导入上按下 F3(Open Declaration) ,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 文件。

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

我假设从 Java 1.8迁移的项目仍然没有 module-info.java。这意味着您正在“未命名模块”中编译代码。

未命名模块中的代码“读取”所有可观察到的已命名和未命名模块,特别是它从 JRE 系统库中读取模块“ java.xml”。该模块导出类似 java.xml.xpath的包。

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

这种情况违反了 JLS 7.4.3(最后一段)中定义的 「独特能见度」的规定。特别是每个限定类型名 Q.Id (JSL 6.5.5.2)都要求其前缀 Q 是唯一可见的包(为简单起见,我不考虑嵌套类型的情况)。因此: 该程序是非法的,必须被编译器拒绝。

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

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

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

(3)解决方案: 除了把你的项目变成一个模块,你还可以通过从可观察模块集中排除 java.xml来避免冲突。在命令行上,这将使用 --limit-modules完成。Eclipse 中的等价物是 “模块化细节”对话框,请参阅 JDT 4.8新的和值得注意的(查找 内容选项卡)。由于 java.xml是通过许多其他默认可观察模块隐式需要的,因此将除 java.base以外的所有模块从右(“显式包含的模块”)推到左(“可用模块”)(并有选择地重新添加项目需要的模块)可能是一个好主意。

PS: Eclipse 仍然没有提供一个理想的错误消息,而不是“无法解决”,它实际上应该说: “包 javax.xml.xpath 可以从多个模块访问: javax.xml,< unname > 。

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

编辑:

  • 亚历克斯巴克利 确认的给定情况是非法的,不管什么 javac 说。针对 javac 的 Bug 被提升为 JDK-8215739。这个 bug 在 Java12发布之前的几个月就已经被承认了。从2019-06年开始,Java13也将在没有补丁的情况下发布。Java14也是如此。这个 bug 被暂时安排在 Java15上,但是这个计划在2020-04-20被放弃了。
  • Eclipse 错误消息 有所改善提到了真正的问题。
  • 在 Eclipse2019-06中,用于解决方案(3)的用户界面是 改造过的

在这里 发生的情况是,您有一个类似于 import org.w3c.dom.*的通配符导入,声明您希望从包 org.w3c.dom中导入所有类。现在,如果 org.w3c.dom中至少有一个类是由第二个源提供的,那么 Java 就不能启动(正如指出的 给你)。

(顺便说一下,在最近的 Eclipse 版本中,消息“ 无法解决”被更准确的错误消息“ 可以从多个模块访问包 org.w3c.dom: < unname > ,java.xml”所取代,参见 Stephan Herrmann 合并的 更改请求。)

来解决这个问题

  1. 打开“ Open Type”对话框(Ctrl + Shift + T)。
  2. 输入 完整导入,即 org.w3c.dom.*org.w3c.dom.
  3. 检查整个列表中的多个源。这里的所有条目应该只包含类似“ jdk-11-...”的内容。
  4. 收集包含您有多个源的类的所有 JAR。
  5. pom.xml打开“依赖层次结构”选项卡。
  6. 搜索 JAR 文件。
  7. 添加一个排除(右键单击或手动编辑 pom.xml)。

例子

在我的 pom.xml中,我有这种对 findbug 的依赖:

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

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

<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是一个(暂时的)依赖项。

据我所知,org.w3c.dom包随后可以从两个模块获得,从而导致构建失败。 如果其中一个依赖项(直接的或暂时的)在 Xml 模块导出的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(bundle org.w3c.dom. Window)
  • xom : 1.2.5(bundle org.w3c.dom. UserDataHandler)
  • stax-api : 1.0.2(包 javax.xml.stream. EventFilter)
  • xml-apis : 1.4.01(bundle org.w3c.dom. Document)
  • xml-beans : 2.3.0(bundle org.w3c.dom. TypeInfo)

虽然斯蒂芬 · 赫尔曼的答案是正确的,但是如果可以帮助别人的话,我会发布我的错误以及我是如何解决它的。我有一个错误 The package javax.xml.namespace is accessible from more than one module: <unnamed>, java.xml,在检查了这个错误的类之后,抱怨的是 javax.xml.namespace.QName导入。在“ Open Type”对话框中,我发现它是从 stax-api通过 eureka 客户端提取的。这解决了我的问题:

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

谢谢你的提示。我无法确定 org.w3c.dom 的引用是从哪里来的。文件。在 Eclipse 2020-12中很容易找到它: Selected org.w3c.dom。在 Eclipse 标记的 import 语句中编写文档,右键单击并选择打开类型层次结构,在类型层次结构对话框中右键单击顶部的 Document 并选择 Developmentors > Workspace 以显示工作区中所有引入 org.w3c.dom 的项目中的所有 JAR。文档(或任何类型,你已经选择,可以从一个以上的模块-MikeOnline 昨天

按照上面的指示,从一个较早的职位帮助我们解决了我们的问题。 我们所做的就是将 Document 替换为 GenericDocument,将 GenericElement 替换为 batik 中的——编译错误消失了——现在我们只需要进行测试,以确保实现与我们在 java 8中的实现相匹配。谢谢 MikeOnline