'Is there anyway to exclude artifacts inherited from a parent POM?
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 on javax.mail:mail-1.4.jar, and ALL-DEPS depends on another version of the same library. Due to the fact that mail.jar from ALL-DEPS exist on the execution environment, although not exported, collides with the mail.jar that exists on the parent, which is scoped as compile.
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>
...
Solution 1:[1]
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 2:[2]
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 3:[3]
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 4:[4]
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>
Solution 5:[5]
Best bet is to make the dependencies you don't always want to inherit intransitive.
You can do this by marking them in the parent pom with scope provided.
If you still want the parent to manage versions of these deps, you can use the <dependencyManagement> tag to setup the versions you want without explicitly inheriting them, or passing that inheritance along to children.
Solution 6:[6]
I really needed to do this dirty thing... Here is how
I redefined those dependencies with scope test. Scope provided did not work for me.
We use spring Boot plugin to build fat jar. We have module common which defines common libraries, for example Springfox swagger-2. My super-service needs to have parent common (it does not want to do so, but company rules force!)
So my parent or commons has pom.
<dependencyManagement>
<!- I do not need Springfox in one child but in others ->
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${swagger.version}</version>
</dependency>
<!- All services need them ->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${apache.poi.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
And my super-service pom.
<name>super-service</name>
<parent>
<groupId>com.company</groupId>
<artifactId>common</artifactId>
<version>1</version>
</parent>
<dependencies>
<!- I don't need them ->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-core</artifactId>
<version>2.8.0</version>
<scope>test</scope>
</dependency>
<!- Required dependencies ->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
</dependencies>
This is size of the final fat artifact
82.3 MB (86,351,753 bytes) - redefined dependency with scope test
86.1 MB (90,335,466 bytes) - redefined dependency with scope provided
86.1 MB (90,335,489 bytes) - without exclusion
Also this answer is worth mentioning - I wanted to do so, but I am lazy... https://stackoverflow.com/a/48103554/4587961
Solution 7:[7]
We can add the parent pom as a dependency with type pom and make exclusion on that. Because anyhow parent pom is downloaded. This worked for me
<dependency>
<groupId>com.abc.boot</groupId>
<artifactId>abc-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
Solution 8:[8]
Repeat the parent's dependency in child pom.xml and insert the exclusion there:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
Solution 9:[9]
When you call a package but do not want some of its dependencies you can do a thing like this (in this case I did not want the old log4j to be added because I needed to use the newer one):
<dependency>
<groupId>package</groupId>
<artifactId>package-pk</artifactId>
<version>${package-pk.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- LOG4J -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
This works for me... but I am pretty new to java/maven so it is maybe not optimum.
Solution 10:[10]
Disable Child Artifact inherited from Parent
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Remove Specific Artifact from Parent
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
