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.