Is there anyway to exclude artifacts inherited from a parent POM?
Asked Answered
B

12

168

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>
...
Broderic answered 21/4, 2010 at 9:40 Comment(1)
that is the reason I hate maven, when things get complicated - I want gradle. with variant aware functionality, in gradle this is not complicated.Guacin
B
63

Some ideas:

  1. 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.

  2. Another thing to test would be to declare the mail artifact with the version required by ALL-DEPS under the dependencyManagement 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>
  1. 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>
  1. 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?!).
Bork answered 21/4, 2010 at 15:28 Comment(1)
Thanks 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)Broderic
F
42

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>
Febrifugal answered 12/11, 2013 at 13:58 Comment(6)
+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.Option
This is also known as the BOM, a.k.a. bill of materials :-)Funke
Does this only work with transitive dependencies? My parent pom contains log4j and it's preventing my pom's logback working properly.Steffi
Hi 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!Ingressive
I 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 a dependencyManagement that redefines the scope properly to test/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.Ingressive
As @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 called import 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.Juanitajuanne
S
20

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.

Steffi answered 21/12, 2017 at 22:1 Comment(3)
Document 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.Corettacorette
Surely 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)Rudiger
No 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.Steffi
P
12

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
Piquet answered 4/1, 2018 at 21:4 Comment(2)
Thank you for your answer, on Windows 10 I had to run notepad empty.class then jar cvf empty.jar empty.class to generate an empty jar.Thitherto
Looks like bad practiceValine
S
7

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>
Subternatural answered 21/4, 2010 at 20:51 Comment(2)
Your 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.Broderic
Scope provided did not work for me. I used scope test, please check my answer. https://mcmap.net/q/143693/-is-there-anyway-to-exclude-artifacts-inherited-from-a-parent-pomNed
D
4

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>
Doncaster answered 11/2, 2021 at 10:22 Comment(0)
A
3

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.

Acree answered 29/10, 2012 at 20:1 Comment(0)
N
3

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://mcmap.net/q/143693/-is-there-anyway-to-exclude-artifacts-inherited-from-a-parent-pom

Ned answered 3/5, 2019 at 12:56 Comment(0)
D
2

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>
Dextrous answered 6/12, 2019 at 14:12 Comment(1)
But you will lose the properties, right?Hasid
L
1

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.

Louie answered 7/6, 2016 at 10:1 Comment(1)
Welcome to Stack Overflow, and don't let the rude people I constantly have dismiss my questions discourage you from posting.Steffi
S
0

Within the <dependencyManagement> make the jar scope=provided

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>group-to-exclude</groupId>
            <artifactId>artifact-to-exclude</artifactId>
            <scope>provided</scope>
        </dependency>

...

Savor answered 25/10, 2023 at 13:52 Comment(0)
N
-1

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>
Northumbrian answered 17/12, 2021 at 12:54 Comment(1)
have you read the actual question?Guacin

© 2022 - 2024 — McMap. All rights reserved.