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

177,318

Solution 1

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?!).

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>
Share:
177,318
Miguel
Author by

Miguel

Updated on December 18, 2021

Comments

  • Miguel
    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 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>
    ...
    
  • Miguel
    Miguel about 14 years
    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)
  • Miguel
    Miguel about 14 years
    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.
  • Matthew Wise
    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
    BitfulByte over 7 years
    This is also known as the BOM, a.k.a. bill of materials :-)
  • Sridhar Sarnobat
    Sridhar Sarnobat over 6 years
    Does this only work with transitive dependencies? My parent pom contains log4j and it's preventing my pom's logback working properly.
  • Sridhar Sarnobat
    Sridhar Sarnobat over 6 years
    Welcome to Stack Overflow, and don't let the rude people I constantly have dismiss my questions discourage you from posting.
  • matbrgz
    matbrgz over 5 years
    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.
  • Amit Goldstein
    Amit Goldstein about 5 years
    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)
  • Sridhar Sarnobat
    Sridhar Sarnobat about 5 years
    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.
  • Yan Khonski
    Yan Khonski about 5 years
    Scope provided did not work for me. I used scope test, please check my answer. stackoverflow.com/a/55970293/4587961
  • Rov
    Rov almost 5 years
    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.
  • Piotr Żak
    Piotr Żak about 4 years
    Looks like bad practice
  • Gerard Bosch
    Gerard Bosch over 3 years
    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!
  • Gerard Bosch
    Gerard Bosch over 3 years
    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.
  • haridsv
    haridsv over 2 years
    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.