How to exclude a dependency for a specific scope only? - maven

I have two dependencies in my pom called A and B. Both A and B have a transitive dependency on an artifact C (cassandra-all). A and B use difference versions of C. Dependency A is the artifact astyanax.
I want to keep the Version of C that comes with B. I accomplished by adding an exclusion in A (Astyanax) for C.
Unfortunately, I want the scope of B to be 'test'. This means that with the exclusion in A, C will not be included outside of the test scope.
How can I resolve this? Can an exclusion be for a specific scope only? Alternatively, can I specify which version to use for a transitive dependency?
Example:
Here is what my pom looks like:
Artifact A (astyanax) with exclusion of dependency on Artifact C (called cassandra-all)
<dependency>
<groupId>com.netflix.astyanax</groupId>
<artifactId>astyanax</artifactId>
<version>1.0.4</version>
<exclusions>
<exclusion>
<groupId>org.apache.cassandra</groupId>
<artifactId>cassandra-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>
<version>1.1.1.1</version>
<scope>test</scope>
</dependency>
So concretely: how can I include cassandra-all when I run code outside of the test scope and still keep the scope of cassandraunit test only?

I apologize if my question wasn't as clear as it could have been. The way I resolved this wasn't hard at all:
I added a separate dependency for C in my pom
I kept the exclusion of C in A
Concretely here, I just added:
<dependency>
<groupId>org.apache.cassandra</groupId>
<artifactId>cassandra-all</artifactId>
<version>1.1.5</version>
</dependency>
and also the following dependency that was missing at runtime otherwise.
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

I am not sure I understood everything, but, in any case, you should be able to achieve this with profiles.
In your pom, create a profile A in which you add your dependency A with exclusion of B and a profile B in which you'll have a dependency with exclusion of A.
On runtime, depending on which of the profile you have selected you'll include one or the other.
HIH

So concretely: how can I include cassandra-all when I run code outside of the test scope and still keep the scope of cassandraunit test only?
Use Maven POM to configure surefire-maven-plugin and change your classpath.
If what you want is only that the cassandra-all dependency be removed from the classpath while running your tests, then the following POM snippet would make the tricky:
<build>
<!-- ... -->
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<classpathDependencyExcludes>
<classpathDependencyExcludes>
org.apache.cassandra:cassandra-all
</classpathDependencyExcludes>
</classpathDependencyExcludes>
</configuration>
</plugin>
</plugins>
</build>

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: '*'
}

How to resolve "Dependency convergence error" when using maven enforcer plugin?

I am just trying to pickup with maven-enforcer-plugin using a small pom (before I jump in to my project pom which has 100+ dependencies.)
After I have added the enforcer plugin, I am seeing Dependency convergence error.
The pom.xml file is below (sorry its not tidy).
How can i fix the errors with out disabling the enforcer plugin.
Basically I want to understand the concept behind how to use dependencyConvergence rule.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>enforcer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.4.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>dependency-convergence</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
</execution>
</executions>
<configuration>
<rules>
<dependencyConvergence />
</rules>
</configuration>
</plugin>
</plugins>
</build>
</project>
Does it mean that, I have to declare each non converging dependency in the dependencyManagement explicitly as in this version of pom.xml(added dependencies to dependencyManagement).
The problem with spring-context still exists as I have added it as direct dependency and then in the dependency management with different version.
Basically - am able to fix the error, but not able to grasp the rules crystal clear yet.
fix one - pom.xml - updated the version in dependency management to the one used explicitly. So now there is no need to give the version explicitly in dependencies. But this would require me to have access to dependencyManagment of parent pom. If my statement is right, this might not be the situation every time.
fix two pom.xml - excluded spring-context from spring-security-web and it worked. But if there are a dozen of exclusion to be done, its going to be a pain.
If this is the way to go about with the convergence rule? In an enterprise project with 100+ dependencies and 100+ of their transitive dependencies, then the Bill of Materials(BOM) is gonna be quite huge and take time to build. hhhmmm. (I agree, there is going to be more control over the versions used and using property like <xyz.version>, upgrades can be done easily).
I will very much appreciate if anyone can list down the rules involving convergence.
A dependency convergence error means that
the dependency is not in dependencyManagement
there are different versions of the dependency in the dependency tree
The typical resolution is to define an entry in dependencyManagement that resolves the issue or to import an appropriate BOM into the dependencyManagement.
This is best done in the main POM of a multi module project, but also possible in modules.
Note that it is better to leave out the <version> tag in the <dependencies> section so that dependencyManagement will be used everywhere.

In Maven, including dependency via <dependency> OR importing the package inside <Import-Package>. Which one of the two should be used?

In my project core pom.xml, there is Import-Package javax.inject;version=0.0.0 and also following maven dependency. I am not clear why both are being used? I mean, if we are already including the dependency via below-mentioned method, then why do we need to use the same inside Import-Package?
<configuration>
<instructions>
<Import-Package>
javax.inject;version=0.0.0,
org.xbc.web.core.service;version=0.0.0,
*
</Import-Package>
<Sling-Model-Packages>
org.xbc.core
</Sling-Model-Packages>
</instructions>
</configuration>
Above mentioned packages are duplicated in below dependencies
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>org.xbc.web</groupId>
<artifactId>fullton-project.core</artifactId>
<scope>provided</scope>
</dependency>
The same scenario is happening in my project. My project A is dependent on project B, there also I have noticed that package path has been added in Import-Package and dependency has been added for project B in core/pom.xml of Project A. why both? Somebody, please clarify this.

What should I do about dependency conflicts when using the maven-shade-plugin?

I'm using the maven-shade-plugin to create an executable jar that contains all of my project's dependencies. Sometimes, these dependencies bring in dependencies of their own that clash with the dependencies of other libraries, and the maven-shade-plugin warns me that it isn't sure which version to include in the uber jar.
[WARNING] maven-shade-plugin has detected that some .class files
[WARNING] are present in two or more JARs. When this happens, only
[WARNING] one single version of the class is copied in the uberjar.
[WARNING] Usually this is not harmful and you can skeep these
[WARNING] warnings, otherwise try to manually exclude artifacts
[WARNING] based on mvn dependency:tree -Ddetail=true and the above
[WARNING] output
In general, my response to this warning is to use the <exclusions> element of the dependency declaration in my pom file to remove the offending dependencies from my project:
<!-- Amazon ElastiCache Client -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>elasticache-java-cluster-client</artifactId>
<version>1.0.61.0</version>
<exclusions>
<!-- this junit dependency clashes with our test-scoped one and causes integration tests to fail to run -->
<exclusion>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
</exclusion>
<!-- this dependency brings in two versions of cglib that clash with one another -->
<exclusion>
<groupId>jmock</groupId>
<artifactId>jmock-cglib</artifactId>
</exclusion>
<!-- newer versions of these dependencies come with dropwizard-core -->
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
When I do this, I use mvn dependency:tree to make sure that I'm excluding the lower version of the offending dependency, in hopes that the newest version is the most mature and bug free.
Cases like the one above that end up with a lot of exclusions raise two questions about this practice:
In the example above, why do I have to manually exclude junit and jmock? Both of these dependencies are marked as <scope>test</scope> in the elasticache-java-cluster-client pom.xml, so I would expect that they wouldn't be included in the jar that I get from maven.
While my practice of always taking the newer version of a dependency seems to have worked so far, I'm afraid that one of these days I'm going to break something. Is there a better way to determine which version of an dependency to keep?
Have you tried adding the maven-enforcer-plugin with the DependencyConvergence rule? This worked well for me in combination with the shade plugin. It will tell you which artifacts are bringing in different versions of the same classes. It allowed me to find out what I have to exclude.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<DependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>

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