Resolve multiple SLF4J bindings in maven project
Solution 1
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.
Solution 2
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'
}
Solution 3
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.
![shabunc](https://i.stack.imgur.com/M35XG.jpg?s=256&g=1)
shabunc
Just another javascripter, coding since 1998, wanna sleep.
Updated on July 05, 2022Comments
-
shabunc almost 2 years
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?
-
shabunc almost 12 yearscan you, please, be more specific, I still don't get how setting classpathScope will help resolve this very problem.
-
Byter almost 12 yearsThe issue is caused due to transitive dependency of gossip jar used. The above code will exclude the dependency of sl4j implementation from gossip.
-
Tom Anderson almost 12 years"Something like this" here means "the Maven equivalent of this Gradle code"!
-
Byter almost 12 years@TomAnderson ya...sorry i didnt mention that :)
-
shabunc almost 12 years@Byter can you, please, provide a maven equivalent, since I still don't get what do you exactly mean. If you mean I should add this exclusions as well, this won't work - as I've already tell in the question, dependency:tree already does not consider gossip/slf4j dependency to be a part of the project.
-
shabunc almost 12 yearsso, you mean I can exclude gossip dependency for free, without any dramatic consequences? ))) Well, and if there are even more dependencies which, in turn, depend on slf4j, it will quickly become, well, a nightmare (((
-
Tom Anderson almost 12 yearsThe only way to make SLF4J happy is to either remove your dependency on Logback, or exclude gshell-io's dependency on Gossip. However, i can't promise that this won't have dramatic consequences. I would hope it doesn't - it would be very poor for a library to have a direct dependency on a logging implementation.
-
Byter almost 12 yearsThe issue is because of 2 different providers... gossip jar has a slf4j implementation within it.. so you either should remove logback or gossip from your dependency tree..
-
Tom Anderson almost 12 yearsThe way you can check if gshell-io has a real Gossip dependency is to download the jar (or the source), and search for references to types from Gossip. If there are none, you are safe. If there are some, you might still be safe it the code was carefully written.
-
Tom Anderson almost 12 yearsHowever, i have just had a look, and it seems that it was not carefully written. There are direct dependencies - see Closer.log, StreamJack.log and Flusher.log. This is really bad. Whoever wrote that code should go to jail.
-
shabunc almost 12 years@TomAnderson, I guess this is the answer, thank you very much. Yet I have one last question. You've said that "it would be very poor for a library to have direct dependency on a logging". Does this mean that it's almost always to wrap logging dependency, thus creating transitive dependency?
-
Tom Anderson almost 12 years@shabunc: What i mean is that the code can have a direct dependency on a logging API (in this case, SLF4J), but should not depend on a specific implementation. That way, it's up to the user of the code (in this case, you) to choose the right implementation. It's even okay for a library to specify a runtime dependency on a particular implementation, to supply a default, but it should tolerate that dependency being excluded and replaced. It's like when you use JDBC - you depend on the JDBC API, but not on classes from a particular driver.
-
shabunc almost 12 years@TomAnderson, thanks again. It's a pity I can not upvote twice :)
-
Tom Anderson almost 12 yearsPS to Jason Dillon in case he ever reads this comment thread: i don't actually think you should go to jail. That's just a figure of speech hyperbolically expressing the opinion that improvements could be made to the code in question. I think community service or a fine would be sufficient.