How to exclude jars generated by maven war plugin?

Viewed 95115

Because of transitive dependencies, my wars are getting populated by xml-apis, xerces jars. I tried following the instructions on the reference page for maven-war-plugin but it is not working.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
      <packagingExcludes>WEB-INF/lib/xalan-2.6.0.jar,WEB-INF/lib/xercesImpl-2.6.2.jar,WEB-INF/lib/xml-apis-1.0.b2.jar,WEB-INF/lib/xmlParserAPIs-2.6.2.jar</packagingExcludes>
      <webXml>${basedir}/src/main/webapp/WEB-INF/web.xml</webXml>
      <warName>project1</warName>
      <warSourceDirectory>src/main/webapp</warSourceDirectory>
    </configuration>
</plugin>

What am I doing wrong ? If it matters, I discovered that the maven-war-plugin I'm using is at version 2.1-alpha-1

9 Answers

You can mark these dependencies as provided:

<dependency>
  <groupId>xerces</groupId>
  <artifactId>xerces</artifactId>
  <version>2.4.0</version>
  <scope>provided</scope>
</dependency>

This way the maven will add them to the compilation classpath, but will not package them. It is assumed they exist in your servlet container.

See more about maven scopes here under "scope"

Edit If you want to remove classes added via transitive dependencies you can exclude them from the dependency like this:

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5.6</version>
        <exclusions>
                <exclusion>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                </exclusion>
        </exclusions>
</dependency>

(taken from this answer)

See more here

I fixed it.

Rereading the reference with a bit more care, I discovered that the element packagingExcludes should be warSourceExcludes.

The correct solution is to use the <packagingExcludes> configuration, as the <scope>provided</scope> solution is a hack.

Consider the following multi-module project:

        A
      (war)
      /   \
     B     C
   (jar) (jar)
    /     /
   D     /
 (jar)  /
 / | \ /
e  f  g

In this multi-module project, module A requires modules {B, C, D}, but not {e, f, g}. However, modules B and D do require {e, f g}, and C requires {g}.


First, let's try to solve this problem with the <scope>provided</scope> approach:

To exclude {e, f, g} from A, the <scope>provided</scope> spec must be present in D's POM. But wait, B requires {e, f, g}. So to fix that, the dependency declarations for {e, f, g} must be present in B's POM as well (with <scope>provided</scope>). This means that the dependency spec complexity from D must be been pulled into B. Similarly, since C depends on {g}, the dependency declarations for {g} must be present in C's POM.

With the the <scope>provided</scope> solution, modules B, C, and D must all have knowledge of the fact that A cannot have {e, f, g}.

This approach breaks the encapsulation principle, and is not practical in multi-module projects that have complex dependency graphs.


Second, let's try to solve this problem with the <packagingExcludes> approach:

To exclude {e, f, g} from A, one must provide the following in A's POM:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
      <packagingExcludes>B*.jar,C*.jar</packagingExcludes>
    </configuration>
</plugin>

With this solution, the complexity of "what must be excluded from A" is contained solely in A's POM. This frees modules B, C and D from having to care about excluding transitive dependencies for the sake of A.

This solution upholds the encapsulation principle.

Related