为什么Maven选择1.0.b2版本而不是1.3.03版本?

8

我有一个依赖于HTTP Builder的项目,这给了我以下依赖关系树:

[INFO] +- org.codehaus.groovy.modules.http-builder:http-builder:jar:0.5.1:compile
[INFO] |  +- org.apache.httpcomponents:httpclient:jar:4.3.2:compile
[INFO] |  |  \- commons-codec:commons-codec:jar:1.6:compile
[INFO] |  +- net.sf.json-lib:json-lib:jar:jdk15:2.3:compile
[INFO] |  |  +- commons-beanutils:commons-beanutils:jar:1.8.0:compile
[INFO] |  |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.4:compile
[INFO] |  |  \- net.sf.ezmorph:ezmorph:jar:1.0.6:compile
[INFO] |  +- net.sourceforge.nekohtml:nekohtml:jar:1.9.9:compile
[INFO] |  |  \- xerces:xercesImpl:jar:2.8.1:compile
[INFO] |  |     \- xml-apis:xml-apis:jar:1.3.03:compile
[INFO] |  \- xml-resolver:xml-resolver:jar:1.2:compile

在我添加了hibernate-entitymanager之后,xml-apis:aml-apis的版本发生了变化。突然间Maven更喜欢使用通过dom4j的传递依赖而来的1.0b2版本:
[INFO] +- org.hibernate:hibernate-entitymanager:jar:4.3.1.Final:compile
[INFO] |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  +- org.jboss.logging:jboss-logging-annotations:jar:1.2.0.Beta1:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:4.3.1.Final:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  \- org.jboss:jandex:jar:1.1.0.Final:compile
[INFO] |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO] |  |  \- xml-apis:xml-apis:jar:1.0.b2:compile

由此,在运行时我现在会得到以下异常:
java.lang.IncompatibleClassChangeError: 
Class org.apache.xerces.parsers.AbstractSAXParser$LocatorProxy 
does not implement the requested interface org.xml.sax.Locator

我知道我可以通过在pom.xml中手动添加具有正确版本号的依赖项来解决它,但我想知道为什么需要这样做:

    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.3.03</version>
    </dependency>
2个回答

9
默认情况下,当在依赖树中发现相同的依赖项时,Maven会使用距离根节点最近的一个依赖项。
在您的情况下,这意味着:
 org.hibernate:hibernate-entitymanager:jar:4.3.1.Final:compile
    \- dom4j:dom4j:jar:1.6.1:compile
       \- xml-apis:xml-apis:jar:1.0.b2:compile 

Vs

 org.codehaus.groovy.modules.http-builder:http-builder:jar:0.5.1:compile
    \- net.sourceforge.nekohtml:nekohtml:jar:1.9.9:compile
       \- xerces:xercesImpl:jar:2.8.1:compile
          \- xml-apis:xml-apis:jar:1.3.03:compile

或者换句话说,3级嵌套与4级嵌套相比,1.0.b2胜出。 为了解决这个问题,要么在对hibernate-entitymanager的依赖中排除xml-apis,要么明确声明对xml-apis的依赖(尽管您可能需要稍微调整一下,Xerces及其依赖关系可能很难对齐版本)。

1
xml-apis 总是一个痛点。它实际上必需的最后一个 Java 版本是 1.4(自从 Java 5 以来,相关类默认在 JRE 类库中),但是有太多不同的东西依赖于它,而且这些依赖版本也存在很多冲突。我希望有一种方式可以指定全局排除 - "无论来源,忽略所有对 xml-apis 的依赖"。 - Ian Roberts
1
xml-apis并不是唯一的痛点...xercesImpl也是臭名昭著的。如果可以的话,尽量避开它。 - eis
1
有趣的是,我一直以为Maven会选择更高的版本来解决依赖关系。 - Vinay Lodha
很多版本字符串不仅仅是数字。 2003 版本比 1.1 更好吗?或者 1.1b1.0.1 更好?alphabeta 更好吗?但反过来说,选择最低公因数以确保事情运作良好可能更有意义。没有一个正确答案,所以最接近胜利的策略是任何策略中最好的。 - eis
1
@VinayLodha,最近者胜利原则适用于同一pom的范围内。简而言之,在这种情况下,据我所知,它取决于它们在pom中定义的顺序。 - eis
显示剩余3条评论

1

这是必要的,因为Maven无法知道应该选择哪个版本,所以Maven使用最近获胜策略来选择使用哪个版本。最近获胜策略在Maven文档中有详细说明。

在您提供的依赖树中,版本1.0.b2显然是最近的,因此行为就像设计的一样正常工作。

您可能需要查看这个主题, 其中此问题曾被讨论过(我无法确定该主题是否与此重复)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接