Is there anyway to exclude artifacts inherited from a parent POM?
Solution 1
Some ideas:
Maybe you could simply not inherit from the parent in that case (and declare a dependency on
base
with the exclusion). Not handy if you have lot of stuff in the parent pom.Another thing to test would be to declare the
mail
artifact with the version required byALL-DEPS
under thedependencyManagement
in the parent pom to force the convergence (although I'm not sure this will solve the scoping problem).
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>???</version><!-- put the "right" version here -->
</dependency>
</dependencies>
</dependencyManagement>
- Or you could exclude the
mail
dependency from log4j if you're not using the features relying on it (and this is what I would do):
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
</dependency>
- Or you could revert to the version 1.2.14 of log4j instead of the heretic 1.2.15 version (why didn't they mark the above dependencies as optional?!).
Solution 2
You can group your dependencies within a different project with packaging pom
as described by Sonatypes Best Practices:
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>
and reference them from your parent-pom (watch the dependency <type>pom</type>
):
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
Your child-project inherits this parent-pom as before. But now, the mail dependency can be excluded in the child-project within the dependencyManagement
block:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Solution 3
Don't use a parent pom
This might sound extreme, but the same way "inheritance hell" is a reason some people turn their backs on Object Oriented Programming (or prefer composition over inheritance), remove the problematic <parent>
block and copy and paste whatever <dependencies>
you need (if your team gives you this liberty).
The assumption that splitting of poms into a parent and child for "reuse" and "avoidance of redunancy" should be ignored and you should serve your immediate needs first (the cure is worst than the disease). Besides, redundancy has its advantages - namely independence of external changes (i.e stability).
This is easier than it sounds if you generate the effective pom (eclipse provides it but you can generate it from the command line with mvn help:effective
).
Example
I want to use logback
as my slf4j binding, but my parent pom includes the log4j
dependency. I don't want to go and have to push the other children's dependence on log4j down into their own pom.xml
files so that mine is unobstructed.
Solution 4
Redefine the dependency (in the child pom) with scope
system pointing to an empty jar :
<dependency>
<groupId>dependency.coming</groupId>
<artifactId>from.parent</artifactId>
<version>0</version>
<scope>system</scope>
<systemPath>${project.basedir}/empty.jar</systemPath>
</dependency>
The jar can contain just a single empty file :
touch empty.txt
jar cvf empty.jar empty.txt
Solution 5
Have you tried explicitly declaring the version of mail.jar you want? Maven's dependency resolution should use this for dependency resolution over all other versions.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>VERSION-#</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>ALL-DEPS</artifactId>
<version>1.0</version>
<scope>provided</scope>
<type>pom</type>
</dependency>
</dependencies>
</project>
Miguel
Updated on December 18, 2021Comments
-
Miguel over 2 years
Artifacts from dependencies can be excluded by declaring an
<exclusions>
element inside a<dependency>
But in this case it's needed to exclude an artifact inherited from a parent project. An excerpt of the POM under discussion follows:<project> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>jruby</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <artifactId>base</artifactId> <groupId>es.uniovi.innova</groupId> <version>1.0.0</version> </parent> <dependencies> <dependency> <groupId>com.liferay.portal</groupId> <artifactId>ALL-DEPS</artifactId> <version>1.0</version> <scope>provided</scope> <type>pom</type> </dependency> </dependencies> </project>
base
artifact, depends onjavax.mail:mail-1.4.jar
, andALL-DEPS
depends on another version of the same library. Due to the fact thatmail.jar
fromALL-DEPS
exist on the execution environment, although not exported, collides with themail.jar
that exists on the parent, which is scoped ascompile
.A solution could be to rid off mail.jar from the parent POM, but most of the projects that inherit base, need it (as is a transtive dependency for log4j). So What I would like to do is to simply exclude parent's library from the child project, as it could be done if
base
was a dependency and not the parent pom:... <dependency> <artifactId>base</artifactId> <groupId>es.uniovi.innova</groupId> <version>1.0.0</version> <type>pom<type> <exclusions> <exclusion> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> </exclusion> </exclusions> </dependency> ...
-
Miguel about 14 yearsThanks for your reply. It contains a lot of useful information. Regarding 1) As you have noticed will not be optimal because parent pom no only contains dependencies that transitively will be resolved if base was marked as a dependency, but also common reporting, source management, and other stuff reused among every project in the company. In relation to 2) I tried it, but also specifying artifact's scope as provided, and it worked :). At first, I thought that as compile takes precedence over provided, it won't work, but fortunately I was wrong (child POM overrides parent's configuration)
-
Miguel about 14 yearsYour approach, as Pascal's workaround #2 is also valid, in fact, you also took into account that mail dependency should be declared as provided. Thank you.
-
Matthew Wise almost 10 years+1 for this, although the child pom should be using <dependencies> section rather than <dependencyManagement> since the latter is for managing the versions of dependencies from within a parent pom.
-
BitfulByte over 7 yearsThis is also known as the BOM, a.k.a. bill of materials :-)
-
Sridhar Sarnobat over 6 yearsDoes this only work with transitive dependencies? My parent pom contains log4j and it's preventing my pom's logback working properly.
-
Sridhar Sarnobat over 6 yearsWelcome to Stack Overflow, and don't let the rude people I constantly have dismiss my questions discourage you from posting.
-
matbrgz over 5 yearsDocument this (and the procedure you followed) very carefully as the future maintainers need to redo this if needing to use an updated version of the parent pom.
-
Amit Goldstein about 5 yearsSurely you mean don't use dependencies in parent pom? Parent pom is still very useful to manage dependency versions, and common plugins. Just using it to inject dependency can backfire - we use it only for the must-have dependencies (like a set of essential spring boot starters for a parent for microservices)
-
Sridhar Sarnobat about 5 yearsNo I’m not saying use a lightweight parent pom. Others on your team won’t allow you to trim the parent pom because other apps depend on the junk in the parent pom that you don’t want.
-
Yan Khonski about 5 yearsScope provided did not work for me. I used scope test, please check my answer. stackoverflow.com/a/55970293/4587961
-
Rov almost 5 yearsThank you for your answer, on Windows 10 I had to run
notepad empty.class
thenjar cvf empty.jar empty.class
to generate an empty jar. -
Piotr Żak about 4 yearsLooks like bad practice
-
Gerard Bosch over 3 yearsHi there, is this really known as BOM? I've seen BOMs are only called as such in the context of defining dependencies in a
<dependencyManagement>
block. This approach is different as relies on transitivity to deliver dependencies. Can this be called BOM? Side question: Is there any way to distribute test scope dependencies without hard-declaring it in a parent so they can be excluded? Thx! -
Gerard Bosch over 3 yearsI answer myself to the 2nd question: To distribute non-compile scoped deps, explicitly declare it as
compile
scope in the libraries descriptor POM, and then, define somewhere adependencyManagement
that redefines the scope properly totest/provided
. This way you can deliver dependencies without hard-declaring it in the parent but in a dedicated dependency of dependencies instead. P.S. Still don't know if is considered a BOM or not. -
haridsv over 2 yearsAs @GerardBosch mentioned, this is not same as BOM approach. In BOM approach, the BOM POM declares managed dependencies which are then imported into a project POM using the special
scope
calledimport
and then the project needs to further declare them as direct dependencies. The above approach brings in all required dependencies transitively and would be considered an anti-pattern and not advisable as a generic alternative to BOM.