Why is Maven including multiple versions of the same dependency?

Master_T :

I have a Maven java web app (.WAR) project that includes several libraries, including the Wicket libraries (but I don't think the problem is wicket itself, but rather with maven).

Here's the problem: even tho I only include Wicket 6.20.0, the resulting .WAR contains two copies of the Wicket libraries: 6.20.0 and 6.18.0, as you can see in this screenshot:

enter image description here

Thinking of some conflicting imports I printed the dependency tree using the:

mvn dependency:tree

commnad... but there is no mention of Wicket 6.18.0 in the dependency tree! I also double-checked using Eclipse's "dependency hierarchy" view and I can confirm there's no trace of that import.

I even did a search for string "6.18.0" across the entire workspace with Eclipse, but it's nowhere to be found!

How can I find out what is causing the inclusion of that duplicate version of the library?

davidxxx :

Maven doesn't work in this way.
The resolution of more than one dependency with the same artifactId and groupId but with a different version will result to a single dependency (the version used is no determinist).

The presence of two artifacts with the same artifactId and groupId but with two distinct versions in a same lib folder of the WAR is probably related to one of these :

  • you don't execute mvn clean package but only mvn package.

  • your use a bugged version of the Maven war plugin. Try to update it to check that.

  • you have a Maven plugin that copies Wicket jars 6.18.0 in the WEB-INF/lib folder of the target folder during the build of the component.

  • the maven WAR project you are building has as dependency an artifact of type WAR. In this case, the dependencies of the WAR dependency are so overlaid in the WAR project that you are building.


An interesting Maven issue about duplicated JAR because of WAR dependencies :

JARs with different versions can be in WEB-INF/lib with war as dependencies


Your answer and your comment indicate that actually you have a WAR dependency in your build.
Unfortunately, there is not really a good and long term effective solution to bypass this limitation.

As said in my comment, using the packagingExcludes property of the maven war plugin is a valid workaround for the actual issue :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <!-- ... -->
        <packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
    </configuration>
</plugin>

But beware, using that will do your build less robust through the time. The day where you update the version of the WAR dependency and that in its new version, it pulls again a different version of wicket, you have still a risk to have duplicate jars with two distinct versions in your built WAR.

Using the overlay feature by specifying the overlay element of the maven-war-plugin is generally better as it focuses on the overlay applied for the war dependency. It fixes the problem early. As a result, you could define to exclude any wicket JARs from the WAR dependency :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <version>2.4</version>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>     
        <overlays>
            <overlay>
                <groupId>com.whatever.youlike</groupId> 
                <artifactId>myArtifact</artifactId>
                <excludes>
                    <exclude>WEB-INF/lib/wicket-*.jar</exclude>                 
                </excludes>
            </overlay>
        </overlays>
    </configuration>
</plugin>

This way is better but this is still a workaround.
The day where the dependency WAR is updated and that it pulls new dependencies (other than Wicket) that are declared in your actual build but with different versions, you may finish with the same kind of issue.

I think that declaring a dependency on a WAR artifact should be done only as we don't have choice.
As poms and projects refactoring are possible, introducing a common JAR dependency which the two WARs depend on and that contains only common sources and resources for the two WARs makes really things simpler.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=474601&siteId=1