Is it a standard practice to explicitly exclude dependencies? - java

for example, in my pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.15.0</version>
</dependency>
for some reasons, the dependencies graph is like:
So, there is a conflicting log4j-api (2.7 vs 2.15).
To fix this, I can explicitly exclude log4j-api in the log4j-core dependency. However, is this actually a standard practice since the log4j-api 2.15.0 will always be used anyway due to dependency management.

So first if a app is using log4j-api in version 2.7 this has even not being upgrade for 5 years apart from that I suppose that the api has not being changed (which the api part implies) so you should or could only replace the implementation (log4j-core) and use the more recent version. You can exclude dependencies via the exclusions like this.
<project>
...
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.15.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
This can also being done in dependencyManagement which is even better...In such I would not exclude the api here...

Related

Maven use compile dependency instead of updates

I am not sure if I am framing this correctly
I am using following spring-boot-starter-data-elasticsearch. As you can see the version is 2.5.7.
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.5.7</version>
</dependency>
As you can see there are 2 compile dependencies. One is spring-boot-starter and another is spring-data-elastic-search. For spring-data-elastic-search compile dependency, I want to use 4.2.7 instead of updated version 4.4.2. But, no matter what I do it always picks up version 4.4.2
Is there a way to use the version needed instead of the updated version? Same with internal dependency.
For example since spring-data-elastic-search is 4.4.2, I want internal dependency like rest-high-level-client to follow the actual version instead of updated version.
You should:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.7</version>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>4.2.7</version>
</dependency>

StringUtil defaultIfBlank disappearing after adding kube java client

I'm adding the following dependencies to my maven project:
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>10.0.0</version>
</dependency>
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-extended</artifactId>
<version>10.0.0</version>
</dependency>
However, after adding this, StringUtils.defaultsIfBlank disappears and my code fails to compile. I've tried adding the following exclusions to these dependencies:
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
I found that the StringUtils class that goes into the classpath is coming from io.sundr:sundr-codegen:0.22.0 which is a dependency from Kube and is packed as an uber jar. this seems odd, how do I make the StringUtils in my direct dependency to take precendence?
You can see which version of commons-lang is being pulled in by using the dependency:tree goal. It sounds like perhaps one of these dependencies you list above is transitively bringing in a different version of commons-lang than you are implicitly requiring.

How to replace a transitive dependency library in a maven project

I have a dependency library which is being pulled in by a library which I have included in my POM.
This transitive dependency has been flagged as an operational risk by a security scan and asked to upgrade it to the latest version. I need to understand how that can be done?
I tried excluding the library from the POM and then declare a direct dependency on the latest version of the same transitive dependency but I get classNotFound exception.
Code elaboration:-
Direct dependency -> hibernate-core
Transitive dependency which as been flagged -> ANTLR 2.7.7
The failed fix that I have tried ->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.18.Final</version>
<exclusions>
<exclusion>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>3.0ea8</version>
</dependency>
Please suggest a generic approach to replacing a transitive library.
There is no need for exclusions. You can override transitive dependencies in the <dependencyManagement> like:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>3.0ea8</version>
</dependency>
...
This will override all transitive occurrences of the library with the version you specify.
But this does not protect you from classNotFound exceptions. If you update a library, class names may have changed and your program might break.

Log4j2/slf4j - Should commons-logging.jar be removed from classpath?

My logging dependencies currently look like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.9.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
I noticed that commons-logging.jar is still in my classpath, for some reason. Should I exclude that or doesn't that cause any issues?
I didn't notice any problems so far, but I'm still wondering if that jar would still cause problems somehow.
There are dependencies that use commons-logging. If it's not present, you'll get NoClassDefFoundErrors when they attempt to log. If there were a possibility to have those not even try to use the dependency, it wouldn't be a problem. However that's not very likely.
However, if they use commons-logging but you're using SLF4J, then there's a problem. They're logging in the wrong place (from your point of view). This is where logging bridges come to work. They implement the public API of different logging frameworks, but redirect the logging to what you're using.
For SLF4J there are several bridges (both ways), so instead of bringing in commons-logging, you bring in jcl-over-slf4j. Libraries will think they're using commons-logging, when they're actually using SLF4J (which then uses an actual logging implementation like Logback).
Easy, huh? ;)
Yes, exclude the commons-logging dependency and add the log4j-jcl bridge instead:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
</dependency>
SLF4J API is also redundant because it is already a transitive dependency of the log4j-slf4j-impl binding.

Why is Gradle excluding required dependencies?

Environment: Linux, Artifactory, Java web apps, Gradle 2.12 with Spring dependency management plug-in and Flyway plug-in.
We are NOT using the Artifactory plug-in. We are just hitting it as if it were a generic maven repository.
Project is massive with something between 80 and 90 sub-projects. We have had several people working on migrating it over from Maven but there have been many headaches. We've beaten most of them but this particular series of knots is very close to sinking us.
Problems:
The build is not faster than Maven using --daemon and not --parallel. This seems pretty weird. Profiling shows that dependency resolution is taking a very long time.
Some aspect of the build is not stable. This is to say that we get various compiler issues when we try to build. This happens regardless of whether we use --parallel or not, although it happens to a greater degree with --parallel. It also happens regardless of local or remote dependencies. We suspect that it is related to some aspect of dependency resolution or perhaps as a result of unexpected exclusion behavior on the part of Gradle. Specifically, we get "Class def not found" and / or "missing symbol". Usually this seems to be related to a transitive dependency. If I put it in explicitly, the error goes away and I get a new one pertaining to a different transitive. I've experimented with putting them in as both transitive and as transitive = false.
Complicating matters, we have many BOMs. Perhaps 10? Some are ours and others belong to 3rd parties. Two or three are more than a page in length.
Without --parallel we can't seem to get the performance we need to justify the migration but we could, perhaps, survive that and wait for --parallel to finish incubating IF we could get it to build reliably. We've been cycling on --debug for about 2 weeks now but our shop is, naturally, inexperienced with Groovy and Gradle.
Clarification: It works about 30% of the time with --parallel and about 90% of the time without. If you build the specific project in question, using the full project path or changing to that sub-directory, there is no problem building.
From the --debug output, for example, I see:
...
-classpath
/development/.../build/classes/main
/development/.../build/resources/main
/home/someUser/.gradle/caches/modules-2/files-2.1/org.springframework/spring-context/4.1.7.RELEASE/8c6c02bcccfa23a74db59f7b7725e69e1af38f04/spring-context-4.1.7.RELEASE.jar
/development/.../build/libs/data-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.hibernate/hibernate-core/4.2.18.Final/2b4c72104fe1910d368d766243f0d0ac2608e134/hibernate-core-4.2.18.Final.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/joda-time/joda-time/2.8.1/f5bfc718c95a7b1d3c371bb02a188a4df18361a9/joda-time-2.8.1.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar
/development/.../build/libs/pnq-orgmanagement-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-stuffmanagement-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.pnq/pnq-someutils/6.7.0-SNAPSHOT/642a90ae7cc4f3f9b281184cacbfa1294f176df8/pnq-someutils-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.eaio.stringsearch/stringsearch/2/44618501b2fb6b2d1bb851d00b264a6eaf1fc0b0/stringsearch-2.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk15on/1.52/88a941faf9819d371e3174b5ed56a3f3f7d73269/bcprov-jdk15on-1.52.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/commons-collections/commons-collections/3.2.1/761ea405b9b37ced573d2df0d1e3a4e0f9edc668/commons-collections-3.2.1.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/commons-codec/commons-codec/1.10/4b95f4897fa13f2cd904aee711aeafc0c5295cd8/commons-codec-1.10.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.springframework/spring-beans/4.1.7.RELEASE/e52148e9671e2918a2172c9cf56b77bede2042ce/spring-beans-4.1.7.RELEASE.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/commons-validator/commons-validator/1.4.1/2231238e391057a53f92bde5bbc588622c1956c3/commons-validator-1.4.1.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.springframework/spring-orm/4.1.7.RELEASE/d8923bdffe631904899875e719d8b363bc3deaea/spring-orm-4.1.7.RELEASE.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.javolution/javolution-core-java/6.2.0rc3/5bae18008a0182d80155dbbe2c91d8907d2496d/javolution-core-java-6.2.0rc3.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.springframework/spring-tx/4.1.7.RELEASE/3465a5d3b24006d51482cf45abd13e347f64582a/spring-tx-4.1.7.RELEASE.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.6.1/6f3b8a24bf970f17289b234284c94f43eb42f0e4/slf4j-api-1.6.1.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.pnq/pnq-batchutils/6.7.0.2/9c025552239645478a759267748c73f3e1e43a47/pnq-batchutils-6.7.0.2.jar
/development/.../build/libs/pnq-mailutils-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.pnq/pnq-utilities/6.7.0.2/d1e8ad707ebd2eddbb29eb0052c05b34acd98b46/pnq-utilities-6.7.0.2.jar
/development/.../build/libs/pnq-database-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.twilio.sdk/twilio-java-sdk/3.3.9/133f7bde99aefae1df78ecd9787e5e60bc521ad2/twilio-java-sdk-3.3.9.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.apache.velocity/velocity/1.7/2ceb567b8f3f21118ecdec129fe1271dbc09aa7a/velocity-1.7.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/javax.mail/mail/1.4.1/8b7bc69010655425dabf091b51d1e90b4de36715/mail-1.4.1.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/org.apache.httpcomponents/httpclient/4.5/a1e6cbb3cc2c5f210dd1310ff9fcb2c09c0d1438/httpclient-4.5.jar
/development/.../build/libs/pnq-infoassembler-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-stufflookup-6.7.0-SNAPSHOT.jar
/home/someUser/.gradle/caches/modules-2/files-2.1/com.pnq/pnq-rcrtrlss/6.7.0-SNAPSHOT/58d6caa20da9035ce7b311f54915448c5bb903dc/pnq-wierdorules-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-cmanagement-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-translation-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-eutilities-6.7.0-SNAPSHOT.jar
/development/.../build/libs/pnq-control-6.7.0-SNAPSHOT.jar
/development/../database/build/libs/test-pnq-database-6.7.0-SNAPSHOT.jar
...
14:50:06.439 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder] junit:junit is excluded from com.project:project-enterprise-test:6.7.0.2(default).
...
st.java:3: error: package org.junit does not exist
14:50:06.481 [ERROR] [system.err] import static org.junit.Assert.assertEquals;
14:50:06.481 [ERROR] [system.err] ^
Note: A global search shows there are NO excludes for junit anywhere in the Gradle build. Also, what DON'T I see in the -classpath? Junit.
...but in the relevant build.gradle file I see:
testCompile ("com.project:project-enterprise-test")
The above is a BOM containing Maven dependencies:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-integration</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<dependency>
<groupId>org.fitnesse</groupId>
<artifactId>fitlibrary</artifactId>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
</dependency>
<dependency>
<groupId>net.sf.dbfit</groupId>
<artifactId>dbfit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>com.springsource.org.apache.commons.io</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>net.servicefixture</groupId>
<artifactId>servicefixture</artifactId>
</dependency>
</dependencies>
In the root build.gradle:
dependencyManagement {
...
imports {
mavenBom "com.project:project-enterprise-test:$bomversion"
}
...
}
It's really hard to help you if you don't include
related build.gradle snippets
the actual errors
For the dependency version mismatches, I suggest that you compare
mvn dependency:tree against gradle dependencyInsight to see what's different.
Maven and Gradle have different ways of dealing with multiple versions of the same dependency within the dependency hierarchy.
Maven uses a "nearest definition wins" strategy.
By default, Gradle will choose the latest version (or you can also define a custom ResolutionStrateegy)

Categories

Resources