Maven: test vs. transitive compile [duplicate] - java

This question already has answers here:
Maven dependency within dependency with different scope
(4 answers)
Closed 6 years ago.
Let's say I have a compile dependency on jar A which has a compile dependency on B. Furthermore, my tests have a dependency on B.
When I declare a "test" dependency on B, this seems to override the transitive compile dependency on B, so that I cannot compile my project anymore. If I leave out B, everything works, but it feels strange because I use a transitive dependency directly.
What would be a "Maven-like" solution for this?
EXAMPLE:
If I only have
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
then my dependency:list is:
commons-codec:commons-codec:jar:1.2:compile
commons-httpclient:commons-httpclient:jar:3.1:compile
commons-logging:commons-logging:jar:1.0.4:compile
The tree is:
--- maven-dependency-plugin:2.8:tree (default-cli) # testcompile ---
de.continentale.spu:testcompile:jar:0.0.1-SNAPSHOT
\- commons-httpclient:commons-httpclient:jar:3.1:compile
+- commons-logging:commons-logging:jar:1.0.4:compile
\- commons-codec:commons-codec:jar:1.2:compile
If I use
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
<scope>test</scope>
</dependency>
Then I get the dependency:list
commons-codec:commons-codec:jar:1.2:compile
commons-httpclient:commons-httpclient:jar:3.1:compile
commons-logging:commons-logging:jar:1.0.4:test
The tree is:
--- maven-dependency-plugin:2.8:tree (default-cli) # testcompile ---
de.continentale.spu:testcompile:jar:0.0.1-SNAPSHOT
+- commons-httpclient:commons-httpclient:jar:3.1:compile
| \- commons-codec:commons-codec:jar:1.2:compile
\- commons-logging:commons-logging:jar:1.0.4:test
So commons-logging changed its scope and is not available any more for compilation.
EDIT2: If I use anything from commons-logging in the src/main/java, then the first version compiles while the second does not. The additional test dependency "hides" the transitive compile dependency.

Have not come across such a situation but if I understood your problem which is the version of dependency B required by your tests and required by dependency A would be different. If the versions are same then you would not have face this issue.
In such case, you could use Dependency Scope feature provided by Maven. Let dependency A get the dependency B of its required version and declare a separate dependency B in your pom with a scope test. That means its usage will be restricted to tests only. You can know more here

Related

Maven transitive dependency - Commons Collection version 3 vs 4

I have such configuration in pom.xml:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
But unfortunately mvn dependency:tree shows me that commons-beanutils has dependency: commons-collections 3.x:
[INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO] | \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.apache.commons:commons-collections4:jar:4.4:compile
I don't want Common Collection 3 in my code but it's possible that someone uses a class from this library by mistake (instead of Common Collective 4, which is preferred version).
As you see in dependency tree - I can't exclude the Common Collection 3, because it is used (can occur java.lang.NoClassDefFoundError).
Question:
How to protect my code base against pollution of Commons Collection 3 API?
You can use the dependency:analyze-only
https://maven.apache.org/plugins/maven-dependency-plugin/analyze-only-mojo.html
to check whether you use undeclared dependencies, i.e. you use a transitive dependency without explicitly declaring it.
If you don't want this in your build, but just check it occasionally, you can use dependency:analyze from the command line.

Maven Dependency with Parent Pom Not Working Properly

I have the following maven structure.
Parent Pom
<dependencyManagement>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.27</version>
</dependency>
</dependencyManagement>
Service Pom
<parent>
<groupId>com.aliseeks.dependencies</groupId>
<artifactId>AliseeksLive</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
</dependency>
</dependencies>
Dependency Conflict:
[INFO] +- org.glassfish.jersey.core:jersey-client:jar:2.27:compile
[INFO] | +- org.glassfish.jersey.core:jersey-common:jar:2.25.1:compile
[INFO] | | +- org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.25.1:compile
Why does Maven pull in JerseyCommon 2.25? JerseyClient 2.27 clearly depends on JerseyCommon 2.25? Is this because JerseyClient 2.27 POM has ${project.version} as a variable and its somehow getting messed up with Dependency Management?
Dependency Tree Dump
jersey-client 2.27 version depends on jersey-common 2.27 version as per following link:
https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client/2.27
But it is definitely pulling 2.25 version of jersey-common after resolving transitive dependencies and maven finds 2.25 version as the nearest child. That's reason it decides to pull 2.25 version.
For the reference that such type of dependency conflict issues can be easily investigated with the help of maven-enforcer-plugin. Following link further explains usage of this plugin with example:
https://dzone.com/articles/solving-dependency-conflicts-in-maven

Confusion regarding jdk.tools in Eclipse/Maven

I have a project that at one point had these lines about jdk.tools
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1.8.0</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
On my Eclipse, removing these lines would gave me an error of
"Missing artifact jdk.tools:jdk.tools:jar:1.8".
But my colleague used the same pom.xml (without those lines) and she did not see
the error.
Also, on a UNIX machine I could maven build without needing
those lines (this is expected, because the scope has been system).
The dependency tree related to this artifact is this:
[INFO] +- org.apache.hadoop:hadoop-common:jar:2.7.3:compile
[INFO] | +- org.apache.hadoop:hadoop-annotations:jar:2.7.3:compile
[INFO] | | \- jdk.tools:jdk.tools:jar:1.8:system

Using Logback but Log4j started displaying WARN no Appenders

I am using logback for my logging and it has been working however; the other day I started getting a warning
log4j:WARN No appenders could be found for logger (org.apache.axis.i18n.ProjectResourceBundle).
log4j:WARN Please initialize the log4j system properly.
I am not using log4j nor have I ever with this project.
I have a logback.xml in my resources folder.
Any ideas on why this warning started to show up?
You must be using a library that does use log4j. Can you post anything more about your project?
You should probably just put log4j bridge on the classpath. Read more here:
http://www.slf4j.org/legacy.html
The jar you want to look into is log4j-over-slf4j. It will bridge log4j API to actually make calls to your implementation of slf4j API (in your case - logback).
If you are using Maven to build your project then it might be as simple as putting
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
in dependencies.
Excluding a library (if needed) would be done in this fashion (this assumes we are talking about the transitive dependency from the jar you've mentioned):
<dependency>
<groupId>org.swift.common</groupId>
<artifactId>jira-soap</artifactId>
<version>4.4.0</version>
<exclusions>
<exclusion>
<groupId>...</groupId>
<artifactId>...</artifactId>
</exclusion>
</exclusions>
</dependency>
Took me some time to find out since the message was log4j:WARN No appenders could be found for logger
I tried to exclude log4j and I tried the log4j-over-slf4j.
Then I ran mvn dependency:tree and finally found out that mye commons-configuration actually was using commons-logging
[INFO] +- commons-configuration:commons-configuration:jar:1.9:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- ch.qos.logback:logback-classic:jar:1.0.13:compile
[INFO] | +- ch.qos.logback:logback-core:jar:1.0.13:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] +- org.slf4j:log4j-over-slf4j:jar:1.7.6:compile
[INFO] \- org.apache.commons:commons-lang3:jar:3.1:compile
This became the solution for me.
<!-- logging with logback (and slf4j)-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<!-- had a dep in commons-configuration -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.6</version>
</dependency>

Resolve multiple SLF4J bindings in maven project

This is a question sounds like bunch of similar questions on SE sites, so I should be quite verbose to make my question clear. So, here is project's minimal pom.xml:
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.shabunc.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Here is the dependency tree produced by maven.
mvn dependency:tree -Dverbose -Dincludes=org.slf4j:
[INFO] [dependency:tree {execution: default-cli}]
[INFO] org.shabunc:logdebug:jar:1.0-SNAPSHOT
[INFO] \- ch.qos.logback:logback-classic:jar:1.0.6:compile
[INFO] \- org.slf4j:slf4j-api:jar:1.6.5:compile
Now, let's remove exclusion and check dependencies again. We'll get:
[INFO] org.shabunc:logdebug:jar:1.0-SNAPSHOT
[INFO] +- ch.qos.logback:logback-classic:jar:1.0.6:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.6.5:compile
[INFO] \- org.codehaus.gmaven.runtime:gmaven-runtime-1.7:jar:1.3:compile
[INFO] +- (org.slf4j:slf4j-api:jar:1.5.10:compile - omitted for conflict with 1.6.5)
[INFO] +- org.codehaus.gmaven.feature:gmaven-feature-support:jar:1.3:compile
[INFO] | \- (org.slf4j:slf4j-api:jar:1.5.10:compile - omitted for conflict with 1.6.5)
[INFO] \- org.codehaus.gmaven.runtime:gmaven-runtime-support:jar:1.3:compile
[INFO] +- (org.slf4j:slf4j-api:jar:1.5.10:compile - omitted for conflict with 1.6.5)
[INFO] \- org.sonatype.gshell:gshell-io:jar:2.0:compile
[INFO] \- org.sonatype.gossip:gossip:jar:1.0:compile
[INFO] \- (org.slf4j:slf4j-api:jar:1.5.8:compile - omitted for conflict with 1.6.5)
So, as we can see, everything works as expected, and conflicting dependency is actually get excluded. But the thing is that even with dependency excluded I still get following message while compiling and calling mvn exec:java:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/shabunc/.m2/repository/ch/qos/logback/logback-classic/1.0.6/logback-classic-1.0.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/shabunc/.m2/repository/org/sonatype/gossip/gossip/1.0/gossip-1.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
The question is: Why I still see this warning and what exactly should be done to make only one version of slf4j reachable during execution?
Your problem isn't getting two copies of the SLF4J API, it's getting two different SLF4J implementations. You need to exclude Gossip, not the API. That means something like:
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.3</version>
<exclusions>
<exclusion>
<groupId>org.sonatype.gossip</groupId>
<artifactId>gossip</artifactId>
</exclusion>
</exclusions>
</dependency>
The Gossip dependency is declared by gshell-io; hopefully, it doesn't actually need Gossip, it just needs an SLF4J SLF4J, which you are supplying in the shape of Logback.
All you need to do is add something like this
compile "org.sonatype.gossip:gossip:1.0" {
exclude module:'slf4j-jcl'
exclude module:'slf4j-log4j12'
}
I guess you need to play with scope of dependencies, see: http://www.mojohaus.org/exec-maven-plugin/java-mojo.html
classpathScope -
defines the scope of the classpath passed to the plugin. Set to compile,test,runtime or system depending on your needs.

Categories

Resources