Eclipse 对导入感到困惑(“可从多个模块访问”)
Posted
技术标签:
【中文标题】Eclipse 对导入感到困惑(“可从多个模块访问”)【英文标题】:Eclipse is confused by imports ("accessible from more than one module") 【发布时间】:2019-08-29 11:05:42 【问题描述】:当引用简单的 .jar 文件时,Eclipse 显示错误说明:
java.awt 包可以从多个模块访问:
, java.desktop
例如,当 javax.awt
或 javax.swing
包含在 .jar 文件中时,就会发生这种情况。
最简单的例子如下:
package test;
import javax.swing.JDialog;
public class Test
public static void main(String[] args)
new JDialog();
将 .jar 文件添加到仅具有文件夹结构 javax/swing
(不需要文件)的类路径将导致出现错误。我正在使用 JDK 10/12(均无效)。将编译器合规性设置为1.8
会使整个事情再次工作。
在另一台带有Eclipse 2018-09
的机器上,编译器合规性设置为10
。
我在 Eclipse 2019-03
上,在(用于测试目的)新安装的 Eclipse 2018-09
上运行良好。为什么?
编辑 2020 年 6 月(解决方案)
正如答案正确指出的那样,这是 Java 很久以前内置的限制,直到最近才强加给我们。我是在将一个有几十个依赖项的大项目迁移到 Maven 时接触到它的。 2000 年左右就有图书馆了!有“元库”,它由几个打包在一起的库组成。 因此,除了确定仍然需要什么(与其余的一起放入垃圾箱!)、更新违反规则的库或找到它们的替代品外,别无他法。这花了我很多很多小时。
最后它成功了,我们有一个不错的 Maven 项目可以使用。
【问题讨论】:
这是Java Platform Module System (JPMS) 的限制,而不是 Eclipse 的限制(所以不要关闭信使)。如果您删除默认包中的文件module-info.java
(禁用 JPMS),它应该可以与 Java 9 或更高版本一起使用。
不创建module-info.java时会发生这种情况。
我上传了一个视频,显示我在新安装的 2019-03 上遇到的问题:youtu.be/6fQ8ZPprVyo
我明白了。解决了将 JRE System Library 从 Modulepath 移动到 Classpath 您的问题吗?
所有内容都必须位于类路径、JAR 和 JRE 系统库(视频仅显示 JAR 位于类路径中)。
【参考方案1】:
这是由引起的
类路径上的JAR,包含包java.awt
也存在于系统库中但是
JRE 系统库在模块路径上
Java Platform Module System (JPMS) 不允许在多个模块中使用同一个包。如果使用 Modulepath 和 Classpath,则 Classpath 上的所有内容都作为 <unnamed>
模块处理(在您的情况下为包 @987654325 @ 存在于系统模块java.desktop
中,也存在于模块<unnamed>
中的类路径 上的JAR。
由于 JRE 系统库 无法从 Modulepath 移动到 Classpath(请参阅this answer by Stephan Herrmann for details),因此您只有以下内容选项:
将编译器合规性设置为 1.8(正如您已经提到的) 重建 JAR 以避免 JAR 中的 Java 系统库包名称(如果使用反射,可能需要进行额外的代码更改): 如果您有源代码,请更改包名称(例如,将包和子包java
更改为 java_util
和 javax
更改为 javax_util
)并重新创建 JAR
如果你只有.class
文件,你必须先反编译.class
文件
【讨论】:
无法将 JRE 添加到 Classpath。 @KrannSock 我已经扩展了我的答案,这是怎么可能的。 @howlher 无论你做什么 - 它都会被添加回 Modulepath。 @KrannSock 是的,你是对的。据我所知,这在以前的版本中是可能的。您可以选择重新打包 JAR 吗? @howlger 感谢您的链接。不幸的是,添加 module-info.java 并不是一个实用的解决方案,因为一旦您这样做,您就要求项目的所有依赖项都是模块,或者至少具有自动模块名称。我的许多依赖项没有 Automatic-Module-Name 标头,因此我必须使用文件名。所以com.google.guava_21.0.0.jar
变为requires com.google.guava.21.0.0
但这是模块信息中的语法错误!捕获 22...【参考方案2】:
由于我敢打赌,很多人会在使用模块化 Java 时遇到这个问题,所以我会提供帮助并给出真正的答案。当您的项目中有一个依赖项包含使用也在您的项目引用的模块中的包的代码时,会发生此错误。如果您的项目已将源代码兼容性设置为 Java 12 之类的东西,它将开始执行该规则,这在 Java 中一直存在。 “不要在自己的代码中使用属于 JDK 的包。”不幸的是,多年来,许多开发人员和供应商都这样做了。不能再这样了。如果您将项目设置为 Java 12 源代码兼容性,Eclipse 会添加 JDK 模块,其中包括“java.”和“javax.”甚至“jdk.”、“org.w3c”。 ”。这些包可能正在被您的依赖项或其传递依赖项使用。
如何解决:您需要查看它抱怨的包并在包资源管理器中展开“项目和外部依赖项”节点。找出哪个依赖项正在使用该包。然后,您可以简单地从您的项目中排除该依赖项。或者,您可以获取该依赖项的来源(如果有),并使用更改的包重新构建 jar。否则,您必须删除该依赖项并找到该技术的替代品。疼吗?
如果它是一个传递依赖,你通常可以排除它。这是基于 Gradle 的项目的示例。
configurations
all*.exclude group: 'xml-apis'
【讨论】:
"不要在自己的代码中使用属于 JDK 的包。"这句话是什么意思?你是说我不能有package javax.matt
,因为 javax 属于 jdk?
没错。例如,Java“拥有”包“java”,因此不允许使用“java.anything”。 “sun.anything”、“javax.anything”也一样。
导入 javax.xml.parsers.ParserConfigurationException;该声明导致我出现错误。当我展开“项目和外部依赖项”时,我发现 xmlParserAPIs-2.6.2.jar 正在使用包 javax.xml.parsers。所以在 build.gradle 我做了配置 all*.exclude group: 'xmlParserAPIs' 但都是徒劳的【参考方案3】:
另请参阅:The package org.w3c.dom is accessible from more than one module: <unnamed>, java.xml 我回答的地方:
令人失望的是,我没有看到任何编译器标志来显示问题所在的 jar 甚至 -Xlint:module 似乎也没有显示出任何有用的东西,而 eclipse 也没有说明任何问题
我一直在使用这个脚本来查找 java.awt 的来源:
mvn dependency:copy-dependencies -DincludeScope=test -DoutputDirectory=deps
for i in deps/*.jar; do if unzip -l $i| grep -q java.awt; then echo $i; fi ; done
严格来说,您不必指定范围测试,因为这是默认设置,但我已将其包含在内,因为您可能想改用 compile
【讨论】:
jdeps 会在这里帮助查看哪两个包有冲突吗? 这是最有帮助的答案。这使我能够确定导致问题的 2 个罐子。感谢分享!【参考方案4】:就我而言,这是因为我在 POM.xml 文件中包含了一个依赖项(Apache Tika)。
在该依赖项处导入时,我不得不强制排除包含错误类的模块:
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.24.1</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
这样对我有用。
【讨论】:
就我而言,问题出在 org.apache.xmlgraphics batik-transcoder 1.13 和 batik-codec 1.13 的依赖项上。您在此处描述的排除项(适用于 batik 依赖项)对我有用。【参考方案5】:我认为我对这个问题的看法可能有用。
对于 javax.xml.stream
下的类,我遇到了这个错误,该错误来自依赖于 xml-apis
、stax-api
或 geronimo-stax-api
等工件的旧 Maven 项目。
从技术上讲,问题在于其他人已经说过:那些工件暴露了 javax.xml.*
包,而没有任何 Java 模块的意识(它们诞生得更早),所以包会自动转到未命名的模块,这与 同一个包包含在 Java 的最新版本中,它有自己的模块名称(因此同一个包会产生两个不同的模块)。
也就是说,实际的解决方案本质上是使用Maven exclusions 从您的项目中删除这些依赖项,并让它使用 JDK 版本。如果您正在使用另一个构建系统,请使用等效项。理论上,JDK 最新版本可能不向后兼容,实际上我怀疑这些 JSR 规范多年来发生了很大变化,到目前为止,我还没有看到它们的替换有任何问题。
【讨论】:
对冲突的部门列表非常有帮助。谢谢。【参考方案6】:您可以按照其他人的建议排除 xml-apis
,这对我来说很好用,但如果您正在使用旧的 jaxb-api
,请将它们替换为 jakarta.xml.bind-api
:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
当然还有升级您的jaxb-impl
以匹配相同的api:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.3</version>
</dependency>
【讨论】:
【参考方案7】:由于这在 Google 上的排名很高,我将把它放在这里,以防它对某人有帮助。
我在 Java 11 和 xmlbeans 库中发现了一些有趣的行为。 xmlbeans 库是Apache POI 的传递依赖项,这是一个非常流行的用于处理Microsoft Office 文档的库,它用于处理较新Office 格式的内部XML 结构。我已经用 Apache POI 3.9 对其进行了测试,它工作得非常好,尽管 Eclipse 显示了错误。所以,我猜在 Java 11 中这条规则并没有完全执行。
【讨论】:
在更新到 Apache POI 的 5.0.0 时遇到完全相同的问题,将<exclusions><exclusion><groupId>xml-apis</groupId><artifactId>xml-</artifactId></exclusion></exclusions>
添加到 poi-ooxml 依赖项就可以了【参考方案8】:
对于使用 Maven 的 Apache POI 5.0.0 版,在 pom.xml 中:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
修复:“包 javax.xml.parsers 可以从多个模块访问”
【讨论】:
【参考方案9】:我在将 JDK 从 1.8 升级到 11 时遇到了与 eclipse IDE 类似的问题,“可以从多个模块访问包 org.w3c.dom:java.xml”。将 eclipse 从 2019 升级到 2021 并将系统 JDK home 设置为 11 并不能解决它。我不认为这是由存在于类路径的不同 jar 中的“org.w3c.dom”引起的,因为“Order and Export”应该对搜索顺序进行排序。
经过几个小时的搜索和调查,通过将 Java 编译器 - 编译器合规级别设置为 1.8(默认为 11)解决了此问题。
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案10】:对于在引用 org.w3c 或 javax.xml 导入时遇到此问题的任何人,请注意这个模块依赖项:xml-apis 它与 java 默认 xml 类冲突。 一个引用它的大项目叫做 DynamicJasper
【讨论】:
以上是关于Eclipse 对导入感到困惑(“可从多个模块访问”)的主要内容,如果未能解决你的问题,请参考以下文章