How to turn off transitive dependencies for maven projects? - maven

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?

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.

Even though I'm not sure why would you want such a mechanism, and I don't recommend that, only exclude transitive dependencies that you actually don't want where the dependencies which depends on them can some how run without them.
The last point is very important those transitive dependencies are needed by your dependencies in order to work probably.
So despite all the above here you go, there is a plugin from Apache Maven called Apache Maven Enforcer Plugin, one of the built in rules it has is Ban Transitive Dependencies

Related

Gradle dependency with test classifier

I've been trying to reference an artefact without luck.
With maven I have no problem doing this:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.13</artifactId>
<version>3.0.0</version>
<classifier>test</classifier>
</dependency>
Maven selects the correct artefact.
However, with gradle, it always seems to include the artefact without the classifier, no matter what I try:
implementation 'org.apache.kafka:kafka_2.13:3.0.0:test'
I have read the gradle documentation and it suggests this syntax, maybe it has something to do with this specific artefact?
Update
My goal is to use spring-kafka-test. Our internal artefact repository is not set up to use pom resolution, which is why I need to add transitives manually.
I've ruled out the fact that it might be our internal repository by only using maven central; and I get the same results.
I managed to include only the mentioned jar, with:
dependencies {
implementation ('org.apache.kafka:kafka_2.13:3.0.0:test') {
exclude group: 'org.apache.kafka' // or finer grained, if we like
}
...
}
See also: How to specify a classifier in a gradle dependency's dependency?
But
Your assumptions about maven were also wrong:
Maven pulls all! (In module-test-parents no dependencies defined.)
To achieve the same (and even more) in maven we'd also have to:
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.13</artifactId>
<version>3.0.0</version>
<classifier>test</classifier>
<exclusions>
<exclusion> <!--sledge hammer -->
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
<!-- or selectively ... -->
</exclusions>
</dependency>
</dependencies>
In gradle the according would be (tested):
implementation ('org.apache.kafka:kafka_2.13:3.0.0:test'){
exclude group: '*'
}

Why is spring-boot-dependencies in dependencyManagement?

The Spring documentation Using Spring Boot without the parent POM shows that the dependency on spring-boot-dependencies is added to the dependencyManagement section. Is this really correct?
spring-boot-dependencies specifies version properties for all the dependencies. However, these properties are not available in the POM that uses spring-boot-dependencies. Presumably, this is because spring-boot-dependencies is in dependencyManagement.
spring-boot-dependencies only includes dependencyManagement and pluginManagement. So it seems possible to include spring-boot-dependencies as a dependency (not dependencyManagement) without adding unnecessary dependencies.
So why is spring-boot-dependencies to be included as dependencyManagement?
So why is spring-boot-dependencies to be included as dependencyManagement?
Let's say you have a project named projectA and you add the spring-boot-dependencies to the dependencyManagement section in your pom.xml.
<project>
<groupId>com.iovation.service</groupId>
<artifactId>projectA</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<type>pom</type>
<version>1.5.8.RELEASE</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
...
</project>
If you notice closely, you will find that all the Spring Boot dependencies declared under the dependencies section don't need to specify the version. It derives the version from the version of spring-boot-dependencies specified in the dependencyManagement section.
Advantages of Dependency Management
It centralizes dependency information by specifying the Spring Boot version at one place. It really helps during upgrade from one version to another.
Subsequent declaration of Spring Boot dependencies just mentions the library name without any version. Especially helpful in multi-module projects
It avoids mismatch of different versions of spring boot libraries in a project.
No Conflicts.
It's definitely correct. Please see Using Spring Boot without the parent POM!
First, let’s understand what dependency is. So when you are developing an application, you would probably need a number of libraries(normally jar files). It means that your application depends on these libraries. Hence the name dependency.
Now you need a way to assemble all these libraries and manage them in a centralized fashion. This also means that these libraries would be made available at compile time or runtime when needed. This is what dependency management does.
So the process of dependency management involves locating these dependencies and adding them to the classpath.
Maven is a popular dependency management tool which will centralize all dependencies information.

How to say to Maven which dependency to use

Right now I'm migrating legacy project from Spring 1 to bigger version (yeah I know it's 2017). The project has 1 dependency which contains a lot of spring/ibatis dependencies. One of ibatis dependency is version 2.1.6 but migrating spring requires bigger version(2.3.4) I put the new dependency in my pom but maven keeps using the old one. I know that it's not soo good to have 2 different version in the project and the main goal for me is to remove the old big dependency but right now I want to start the project with the new one without removing the old one.
How to tell maven which dependency to use and how to ignore the other one? If this is not possible tell me how to migrate easily.
Thank you.
add the <exclusions> tag under the <dependency> section of the pom.
More Details here
Sample:
<project>
...
<dependencies>
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

How do I indicate to maven that one dependency provides another?

After version 11.0.2, Google's guava library switched to Java 6. Fortunately, for those of us stuck on Java 5, they also released a "guava-jdk5" artifact.
Unfortunately, some of my dependencies pull in guava 11.0.2 transitively. Which leaves my project containing both guava-jdk5 and guava.
Normally when I have conflicting versions, I can use the "dependencymanagement" tag to indicate which version to pull in. But since these are two different artifacts, I do not understand how to do this. Ultimately I want to tell maven, guava and guava-jdk5 are the same artifact and I want the 17.0 version of guava-jdk5 to be the one that is used. How do I do this?
Thanks!
One easy way is to use a dependency exclusion, nutshell from the link:
<project>
...
<dependencies>
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

Excluding some 3rd party jar in ear using maven

I am building an ear using maven <packaging>ear</packaging> tag.
One of the declared dependencies is adding it's transitive dependency to the generated ear. Is there any way to exclude this in the generated ear?
That is, my EAR pom has a dependency on module_A, this somewhere along the tree has a dependency on module_X which is getting packaged in the generated ear.
Is there any way not to include this(module_X) in the ear?
Directly adding an excludes tag for module_X in my pom did not work.
Everything is possible with maven. You just have to simly add a tag exclusions in the pom of your ear, something like that :
<dependency>
<groupId>my.group</groupId>
<artifactId>module_A</artifactId>
<exclusions>
<exclusion>
<groupId>my.group</groupId>
<artifactId>module_X</artifactId>
</exclusion>
</exclusions>
</dependency>
If the dependency is scoped as compile in the parent POM and you need it to be provided within your EAR, you can use dependency management within the child POM where you need to change its scope:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.group</groupId>
<artifactId>transitive-dependency</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>

Resources