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

Car*_*ten 29 java eclipse maven java-10

我正在开发Eclipse中的Maven项目(branch platform-b​​om_brussels-sr7).当我最近尝试切换Java构建路径,为项目JDK 10,Eclipse构建再也找不到类,如javax.xml.xpath.XPath,org.w3c.dom.Documentorg.xml.sax.SAXException.似乎只有XML相关的类受到影响,主要来自Maven依赖xml-apis-1.4.01.

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

我尝试了几件事,但都没有帮助.我试过了:

  • 项目清洁
  • 不同的Eclipse版本:氧气和光子.
  • 使用JDK 8和JDK 10运行Eclipse本身.
  • 更改项目的编译器合规性级别.它在JDK 8构建路径下以符合级别8和10构建,并且在构建路径中使用JDK 10都失败.

Ste*_*ann 33

我认为从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是唯一可见的包(为简单起见,我不考虑嵌套类型的情况)。Ergo:该程序是非法的,必须被编译器拒绝。

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

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

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

(3)解决方案:除了将您的项目变成一个模块之外,您仍然可以通过java.xml从可观察模块中排除来避免冲突。在命令行上,可以使用--limit-modules。Eclipse中的等效项是“模块化详细信息”对话框,另请参见JDT 4.8 New&Noteworthy(查找“ 目录”选项卡)。由于java.xml许多其他默认可观察的模块都隐式需要此模块,因此最好将除java.base右方(“显式包含的模块”)之外的所有内容推至左侧(“可用模块”)(并有选择地重新添加这些模块)您的项目需要的)。

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

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

编辑:

  • 尽管javac怎么说,Alex Buckley 确认给定的情况是非法的。针对Javac的错误已提出为JDK-8215739。在Java 12发行前几个月就已经确认了该错误。从2019-06年开始,已经确定Java 13也将在未修复的情况下发布。
  • Eclipse错误消息已得到改进,以提及实际问题。
  • 在Eclipse 2019-06中,对解决方案(3)使用的UI进行了改进。可以在联机帮助中找到最新文档。

  • 很好的答案。您是否会考虑编写一篇后续文章,为那些不了解模块化编译精确规则的人解释使用新 UI 时应遵循的具体过程?(我想到了我学习Java的学生,我无法一次性教给他们所有Java的复杂性,但仍然希望尽快让他们接触有趣的项目,他们可能会遇到这个困难。) (3认同)
  • @OlivierCailloux埋在[Eclipse错误报告线程中的注释51](https://bugs.eclipse.org/bugs/show_bug.cgi?id=536928)中的这些简短说明对我有用:“排除xml-apis .jar,在eclipse中打开您的POM,转到Dependency Hierarchy选项卡,按xml-api进行过滤,右键单击出现的xml-apis的任何实例,然后选择“排除Maven工件”。 (2认同)
  • 第三种解决方案:从项目依赖项中排除“ xml.apis”。与从可观察模块的集合中排除java.xml相比,缺点在于:1)将xml.apis作为传递依赖项引入的依赖项(在我的情况下为xerces)可能与该特定版本兼容,并且行为不当JRE提供的版本(可能更旧);2)`xml.apis`可能提供JRE提供的版本中未包含的类。但是,排除java.xml模块(其他组件可能依赖于该模块)也存在类似的风险。@StephanHerrmann:有什么想法吗? (2认同)
  • 另外,xml.apis:xml.apis:1.4.01似乎是java.xml的子集(如OpenJDK 11中所提供):我发现前者中没有任何类,但后者没有org.apache.xmlcommons.Version`,但是相反,许多java.xml中的类都不在xml.apis中。因此,我宁愿建议排除xml.apis并保留JRE模块。 (2认同)

Ste*_*ann 14

虽然(我自己)接受的答案仍然是正确的,但这个故事的进一步转折最近引起了我的注意

初衷可能为了实际支持当前的情况。

请参阅原始设计文档“模块系统的状态”(SotMS)中的这段引用:

如果在命名模块和未命名模块中都定义了包,则未命名模块中的包将被忽略。

该文档的日期为 2016/3/8 08:18,并且当时已被标记为“此文档稍微过时”。此外,它对任何实施都不具有法律约束力。该文档仍然具有一定的相关性,因为上面引用的内容正是似乎要实现的内容(并且在JDK-8215739提交javac多年后仍然实现)。

IOW,冲突并不是第一个和第二个实现之间的冲突,而是 Oracle 内部的冲突,看起来如此。2 票支持这种情况(SotMS 和 javac),只有一票反对(JLS)。

由于 Eclipse 提交者不愿意在 Oracle 中解决此冲突,因此最近的 2022-12 版本的 Eclipse 有一个新的编译器选项:通过将以下行添加到项目的.settings/org.eclipse.jdt.core.prefs,用户可以选择在这方面忽略 JLS:

org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage=enabled
Run Code Online (Sandbox Code Playgroud)

此选项将决定权交到用户手中:他们想要 JLS 语义还是 SotMS/javac 语义(在本特定问题中)?尽管如此,我们还没有准备好为其提供 UI 选项,以避免用户在没有此处提供的背景信息的情况下轻率地做出此选择。

就我个人而言,我对这种情况并不是特别满意,因为它加剧了 Java 不是一种语言,而是多种语言这一事实​​。


Gui*_*ume 7

在我的情况下,问题是xercesImpl : 2.10.0(瞬态)依赖。这个 jar 包org.w3c.dom.html.HTMLDOMImplementation

据我了解,该org.w3c.dom软件包可从两个模块中使用,从而导致构建失败。如果依赖项之一(直接或瞬态)在java.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>
Run Code Online (Sandbox Code Playgroud)

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

其他违法者:

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


Gar*_*son 5

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


ste*_*fen 5

这里发生的情况是您有一个通配符导入import org.w3c.dom.*,表示您要从包中导入所有类org.w3c.dom。现在,如果至少有一个类由org.w3c.dom第二个源提供,则 Java 不得启动(如此处指出的

(顺便说一句,消息“ ...无法解析”被替换为更准确的错误消息“ The package org.w3c.dom isaccessible from multiple module: <unnamed>, java.xml ”在最近的版本中Eclipse 版本,请参阅 Stephan Herrmann 的合并更改请求。)

为了解决这个问题

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

例子

我的 中有这个 findbugs 依赖项pom.xml

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>findbugs</artifactId>
    <version>${findbugs.version}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)


jeb*_*det 5

虽然 Stephan Herrmann 的答案是正确的,但如果可以帮助其他人,我将发布我的错误以及我如何解决它。我遇到了错误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>
Run Code Online (Sandbox Code Playgroud)