Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to turn off transitive dependencies for maven projects?

I have come across the JIRA post that gives a solution as including exclusion tag in each dependency tag of POM.

But I have large number of projects and each project has huge number of dependency tags. It's not feasible to include this <exclusion> in each of the dependency tags.

Question: Is there a way to globally switch off the importing of transitive dependencies in maven?

like image 505
A.R.K.S Avatar asked Mar 11 '16 00:03

A.R.K.S


People also ask

How do you remove a transitive dependency?

If a transitive dependency exists, we remove the transitively dependent attribute(s) from the relation by placing the attribute(s) in a new relation along with a copy of the determinant.

How do you exclude transitive dependency of transitive dependency?

Multiple transitive dependencies can be excluded by using the <exclusion> tag for each of the dependency you want to exclude and placing all these exclusion tags inside the <exclusions> tag in pom. xml. You will need to mention the group id and artifact id of the dependency you wish to exclude in the exclusion tag.

How do you change transitive dependency?

How do you do this if the wrong dependency is a transitive dependency? By taking advantage of Maven's nearest definition logic, developers can override the version of a dependency by declaring it on the root pom. xml file.


1 Answers

In Maven you cannot switch off transitive dependencies for all declared dependencies in a single way, as stated by official documentation

Why exclusions are made on a per-dependency basis, rather than at the POM level

This is mainly done to be sure the dependency graph is predictable, and to keep inheritance effects from excluding a dependency that should not be excluded. If you get to the method of last resort and have to put in an exclusion, you should be absolutely certain which of your dependencies is bringing in that unwanted transitive dependency.


Indeed, since Maven 3.2.1 you can specify wildcards to exclude all transitive dependencies for a specific dependency, but that's still per dependency and not global.

What you actually would like to have something like the following per each and every dependency in each and every pom (!!):

<dependency>
    <groupId>groupId</groupId>
    <artifactId>artifactId</artifactId>
    <version>version</version>
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Although this is not advisable since it may easily (and negatively) affect maintainability of concerned projects, a possible solution would be to have a common parent POM for all of the concerned projects, so that each pom would declare:

<parent>
    <groupId>com.sample</groupId>
    <artifactId>projects-governance</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>

Then, in the concerned parent POM you would have:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>modules</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
            <!-- for each and every foreseen dependency of children poms -->
            <dependency>
                <groupId>groupId</groupId>
                <artifactId>artifactId</artifactId>
                <version>version</version>
                <exclusions>
                    <exclusion>
                        <groupId>*</groupId>
                        <artifactId>*</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

Note the dependencyManagement section, here we are saying: to all children POMs, whenever you use the concerned dependencies I declare, for this groupId and this artifacId by default this version and this exclusions will be applied.

The main advantages of this solution is that you centralize this mechanism/management so that at least you don't have to touch each and every POM (except the change concerning the new parent).

However, you would still need to list in the parent POM all the dependencies used by all the projects and apply a wildcard exclusion for all of them.


To get a list of all dependencies per project, you can probably go for a manual approach (open each and every POM!) or run on each project the following:

mvn dependency:list -DexcludeTransitive=true -DoutputFile=dependencies.txt -DappendOutput=true

The Maven Dependency Plugin would then write in the specified dependencies.txt file the declared dependencies (in the format groupId:artifactId:packaging:version:scope) of the concerned project. Note the last parameter, appendOutput, could be helpful to write at the end of the same file in order to keep them centralized for further processing (removing duplicates, moving them to the new parent pom).


To apply wildcards to all declared dependencies, a quick hint is to simply replace (with any text editor or via shell scripting) the following tokens:

    </version>
</dependency>

By the following ones:

    </version>
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Then save the file. And automatically you would have in a quite safe manner applied wildcard exclusions to all dependencies.

Update by OP: Finally we decided not to do this and instead, solve the original problem by using dependency tree command to generate reports of the newly added/removed dependencies for each project and broadcast it.

like image 179
A_Di-Matteo Avatar answered Oct 05 '22 20:10

A_Di-Matteo