CMOS
CMOS

Reputation: 51

Why maven-war-plugin behaves differently than the standard maven dependency resolving mechanism

Is there a reason maven-war-plugin behaves differently than the standard maven dependency resolving mechanism? I have a war maven project which has a dependency:

    <dependency>
        <groupId>GroupA</groupId>
        <artifactId>DependencyA</artifactId>
        <exclusions>
            <exclusion>
                <groupId>GroupB</groupId>
                <artifactId>DependencyB</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

The above dependency is correctly excluded and I can verify on the dependency hierarchy view. When I build the war with maven it includes the DependencyB in WEB-INF/lib directory, so I have to explicitly define to exclude it using the maven-war-plugin as so:

        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <warSourceDirectory>src/main/webapp</warSourceDirectory>
                <packagingExcludes>
                    WEB-INF/lib/dependencyB.jar,
                </packagingExcludes>
            </configuration>
        </plugin>

I have to do the above cause conflicts between versions arise on my project. Why is this happening? Is there another way to achieve this?


UPDATE

So I created a test case just to showcase you what I mean, if I was not clear enough before. And the corresponding pom's are as below:

ArtifactA:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>GroupA</groupId>
<artifactId>ArtifactA</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ArtifactA Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>GroupB</groupId>
        <artifactId>ArtifactB</artifactId>
        <type>war</type>
        <version>0.0.1-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>GroupC</groupId>
                <artifactId>ArtifactC</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>


<build>
    <finalName>ArtifactA</finalName>
</build>

ArtifactB

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>GroupB</groupId>
<artifactId>ArtifactB</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ArtifactB Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>GroupC</groupId>
        <artifactId>ArtifactC</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>
<build>
    <finalName>ArtifactB</finalName>
</build>

ArtifactC

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>GroupC</groupId>
<artifactId>ArtifactC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ArtifatcC</name>
<url>http://maven.apache.org</url>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

In the dependency Hierarchy in Eclipse, I do not see the dependency ArtifactC. enter image description here

And when building the ArtifactA and unzipping the .war I get: enter image description here

As you can see the transitive dependency is included in the .war in the WEB-INF/lib. I hope this is more clear now.

Some other details to add:

  1. I'm calling maven from eclipse
  2. maven-war-plugin version 2.1.1, also tested 2.5
  3. Maven version 3.0.4 embedded in Eclipse

Upvotes: 2

Views: 211

Answers (2)

Adam Gent
Adam Gent

Reputation: 49095

I too have noticed strange behavior with <exclusions>. My best recommendation is to put this in the war project (Project A).

<dependency>
    <groupId>GroupC</groupId>
    <artifactId>ArtifactC</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <scope>provided</scope>
</dependency>

notice the scope provided

I have to do this frequently for commons-logging as something always seems to somehow cause it to be included and its just a pain in the a$$ to go around and mark exclusions everywhere.

The other option is to do this in Project B:

<dependency>
    <groupId>GroupC</groupId>
    <artifactId>ArtifactC</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <optional>true</optional>
</dependency>

Then add the ArtifactC and ArtifactB dependency explicitly where you actually need it (ie deploying B in other places).

notice the optional

Like I said in my comment I don't think its a good idea to rely on <exclusions>. It generally means something is broken. Its particularly bad if your the one causing it.

Upvotes: 0

J&#246;rn Horstmann
J&#246;rn Horstmann

Reputation: 34044

The problem is not so much that the war plugin handles dependency exclusion differently, but that it handles dependencies of <type>war</type> specially. It creates a war overlay out of these, meaning it takes the whole contents of the war and puts the projects web resources on top. The war dependency really has no transitive dependencies, it already includes all jar files.

If using war overlays is really your intention then using packagingExcludes is the correct solution. If you instead want to depend on the classes in artifact B then you should modify the pom so it creates a separate artifact (using the attachClasses configuration) and depend on this classes artifact. Exclusion of transitive dependencies should then work as with any other jar dependency.

Upvotes: 2

Related Questions