Why does Maven choose version 1.0.b2 over 1.3.03
Asked Answered
G

2

8

I have a project with a dependency on HTTP BUilder, this gives me the followoing dependency tree:

[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

After I add hibernate-entitymanager, the version of xml-apis:aml-apis changes. Suddenly Maven prefers to use version 1.0b2 which is a transitive dependency via dom4j:

[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

Due to this, I now get the following exception during runtime:

java.lang.IncompatibleClassChangeError: 
Class org.apache.xerces.parsers.AbstractSAXParser$LocatorProxy 
does not implement the requested interface org.xml.sax.Locator

I know I can fix it by manually adding the dependency with the good version number in my pom.xml, but I wonder why this is needed:

    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.3.03</version>
    </dependency>
Gizela answered 24/4, 2014 at 11:57 Comment(0)
T
9

By Default, when the same dependency is found in the dependency tree, Maven uses a closest one to the root.

In your case, this means

 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

Or to put it another way 3 levels deep vs 4 levels deep so 1.0.b2 wins.

To solve this, either exclude xml-apis from your dependency on hibernate-entitymanager or explicity declare a dependency on xml-apis (though you might have to play with this a bit, Xerces and its dependencies can be a nightmare to get aligned version-wise).

Telium answered 24/4, 2014 at 12:5 Comment(8)
Indeed, seems this is explicitly mentioned in the docs I have noticed now: maven.apache.org/guides/introduction/…Gizela
xml-apis is always a pain point. The last version of Java in which it was actually required was 1.4 (since Java 5 the relevant classes have been in the JRE class library by default) but so many different things depend on it in so many conflicting versions. I wish there were a way to specify a global exclusion - "ignore all dependencies on xml-apis regardless of where they came from".Mozzetta
xml-apis is not the only pain point relevant here... xercesImpl is notorious. Run away if you can.Kristie
Interesting I always thought maven chooses higher version to resolve dependencies.Flavoring
@VinayLodha A lot of version strings aren't just numbers. Is 2003 version better than 1.1? Or 1.1b better than 1.0.1? alpha better than beta? Then again, wouldn't it make more sense to select the lowest common factor to ensure that things would work? There is no one correct answer, so nearest-wins is about as good a strategy as any.Kristie
I also thought that @VinayLodhaGizela
Wonder what will happen when I have 2 dependency at same level with different version.Flavoring
@VinayLodha then nearest-wins is used in the scope of same pom. In short, AFAIK in that case it depends on the order they are defined in pom.Kristie
K
1

It's needed because Maven cannot know which version it should choose, so Maven uses nearest-wins strategy to choose which one to use. Nearest-wins strategy is documented in Maven documentation.

In the dependency tee you've provided version 1.0.b2 is clearly the nearest, so the behaviour is working like designed.

You might want to look at this thread where this has been previously discussed (I couldn't decide if that thread is a duplicate of this or not)

Kristie answered 24/4, 2014 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.