bazel-contrib / rules_jvm_external

Bazel rules to resolve, fetch and export Maven artifacts
Apache License 2.0
337 stars 256 forks source link

Cannot resolve conflicting class path bindings #455

Open friendly-pineapple opened 4 years ago

friendly-pineapple commented 4 years ago

Aloha!

We are currently running into issues with conflicting class path bindings, for an application that's depending on both ch.qos.logback:logback-classic and org.apache.avro:avro-tools.

For example, we're seeing this:

SLF4J: Found binding in [jar:file:/app/maven_install/v1/https/artifactory/maven-release/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/app/maven_install/v1/https/artifactory/maven-release/org/apache/avro/avro-tools/1.8.2/avro-tools-1.8.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]

The root cause is that both of these jars contain the StaticLoggerBinding.class from slf4j:

>_ jar -tf logback-classic-1.2.3.jar
META-INF/
META-INF/MANIFEST.MF
ch/
ch/qos/
ch/qos/logback/
ch/qos/logback/classic/
ch/qos/logback/classic/AsyncAppender.class
ch/qos/logback/classic/BasicConfigurator.class
ch/qos/logback/classic/ViewStatusMessagesServlet.class

... truncated ...

org/slf4j/impl/StaticLoggerBinder.class <---- Here!!!
org/slf4j/impl/StaticMarkerBinder.class
org/slf4j/impl/StaticMDCBinder.class

... truncated ...
>_ jar -tf avro-tools-1.8.2.jar
META-INF/MANIFEST.MF
META-INF/
META-INF/cddl-1.0.text
META-INF/cddl-1.1.text
META-INF/DEPENDENCIES
META-INF/LICENSE
META-INF/mpl-2.0.text
META-INF/NOTICE
org/
org/apache/
org/apache/avro/
org/apache/avro/tool/
org/apache/avro/tool/BinaryFragmentToJsonTool.class
org/apache/avro/tool/CatTool.class
org/apache/avro/tool/ConcatTool.class

... truncated ...

org/slf4j/
org/slf4j/impl/
org/slf4j/impl/Log4jLoggerAdapter.class
org/slf4j/impl/Log4jLoggerFactory.class
org/slf4j/impl/Log4jMDCAdapter.class
org/slf4j/impl/StaticLoggerBinder.class  <---- Here!!!
org/slf4j/impl/StaticMarkerBinder.class
org/slf4j/impl/StaticMDCBinder.class

... truncated ...

That results in both of these being placed onto the class path.

Looking through the rules_jvm_external docs, we saw configuration options for us to exclude entire jars from being pulled in, but we did not see a method to exclude just a single component of a jar. Advice on this matter would be appreciated!

(If this issue is more appropriate to post in https://github.com/bazelbuild/rules_java, we can certainly do that too!)

Thanks in advance!

EArbeitman commented 4 years ago

Hi - I also experienced this issue with multiple bindings found slf4j. Have you tried using the override targets feature:

jin commented 4 years ago

override_targets is probably the way to go, using a genrule pipeline depending on the downloaded logback-classic or avro jar to strip out a particular class file. I don't know of a particular mechanism in the Java ruleset to strip out a particular classfile from a jar, though that would be helpful here.

EArbeitman commented 4 years ago

hey @friendly-pineapple did this particular issue arise at build time or runtime for you? Reason I ask is because my project that depends on slf4j built successfully, but had issues at runtime

friendly-pineapple commented 3 years ago

We have the similar experience -- this happens at runtime for us.

plaird commented 3 years ago

A bit of a tangent, but this is a common and tedious problem for java Spring Boot applications. Spring Boot apps tend to aggregate a large number of deps and so class version conflicts have been more common than we expected. I don't think much of it is general purpose, but just for ideas here we have a set of strategies for dealing with this when using the Spring Boot rule: Detecting, Excluding and Suppressing Unwanted Classes

cheister commented 3 years ago

Can you workaround this by adjusting the classpath order so you load the class you want first?

If you still want to go the route of manipulating a third party jar you could just build a version of the jar without the classes and use that? Or if you want to do this with a rule you could probably use jarjar to process the jar and remove classes you don't want.