Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency Conflict: duplicate classes "org.apache.commons.logging.LogFactory" in different JARs, have different implementations #173

Closed
HelloCoCooo opened this issue Apr 7, 2019 · 2 comments

Comments

@HelloCoCooo
Copy link
Contributor

Hi, in groupon/odo-1.0.0-beta.5 (proxylib module), duplicate classes with the same fully-qualified name org.apache.commons.logging.LogFactory are included in two different libraries, i.e., org.slf4j:jcl-over-slf4j:1.5.10 and commons-logging:commons-logging:1.1.3.

According to "first declaration wins" class loading strategy, only this class in commons-logging:commons-logging:1.1.3 can be loaded, and that in org.slf4j:jcl-over-slf4j:1.5.10 will be shadowed.

By further analyzing, your project expects to invoke method <org.apache.commons.logging.LogFactory: org.apache.commons.logging.LogFactory getFactory()> in org.slf4j:jcl-over-slf4j:1.5.10. As it has been shadowed, so that this method defined in ommons-logging:commons-logging:1.1.3 are actually forced to be referenced via the following invocation path:

<com.groupon.odo.proxylib.BackupService: boolean restoreBackupData(java.io.InputStream)> D:\testcase\TestProject\odo-proxyaggregator-1.0.0-beta.3\proxylib\target\classes
<org.apache.http.impl.client.DefaultHttpClient: void <init>()> D:\cEnvironment\repository\org\apache\httpcomponents\httpclient\4.3.1\httpclient-4.3.1.jar
<org.apache.http.impl.client.AbstractHttpClient: void <init>(org.apache.http.conn.ClientConnectionManager,org.apache.http.params.HttpParams)> D:\cEnvironment\repository\org\apache\httpcomponents\httpclient\4.3.1\httpclient-4.3.1.jar
<org.apache.commons.logging.LogFactory: org.apache.commons.logging.Log getLog(java.lang.Class)> 
<org.apache.commons.logging.LogFactory: org.apache.commons.logging.LogFactory getFactory()>


Although both of these two conflicting classes contain the referenced methods (with the same signature), they have different implementations. This issue will not lead to runtime crashes, but it can introduce inconsistent semantic hehavior by changing the control flows and data flows.

Workaround solution:
An easy way to workaround the problem is reversing the declaration order of these two libraries (i.e., reverse the declaration order of httpclient and jcl-over-slf4j) in pom file.
Then, according to "first declaration wins" class loading strategy, class org.apache.commons.logging.LogFactory in org.slf4j:jcl-over-slf4j:1.5.10 can be loaded (the version that groupon/odo expects to reference by static analysis).
This fix will not affect other libraries or class, except the above duplicate class.

Dependency tree---

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ proxylib ---
[INFO] com.groupon.odo:proxylib:jar:1.0.0-beta.3
[INFO] +- com.groupon.odo:proxyplugin:jar:1.0.0-beta.3:compile
[INFO] +- org.json:json:jar:20090211:compile
[INFO] +- net.sf.flexjson:flexjson:jar:2.1:compile
[INFO] +- commons-lang:commons-lang:jar:2.6:compile
[INFO] +- javassist:javassist:jar:3.12.1.GA:compile
[INFO] +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile
[INFO] | - org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile
[INFO] +- com.fasterxml.jackson.core:jackson-core:jar:2.3.0:compile
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.3.0:compile
[INFO] | - com.fasterxml.jackson.core:jackson-annotations:jar:2.3.0:compile
[INFO] +- com.h2database:h2:jar:1.3.175:compile
[INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:provided
[INFO] +- org.apache.httpcomponents:httpclient:jar:4.3.1:compile
[INFO] | +- org.apache.httpcomponents:httpcore:jar:4.3:compile
[INFO] | +- commons-logging:commons-logging:jar:1.1.3:compile
[INFO] | - commons-codec:commons-codec:jar:1.6:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.5.10:compile
[INFO] +- org.slf4j:jcl-over-slf4j:jar:1.5.10:runtime
[INFO] +- log4j:log4j:jar:1.2.15:runtime
[INFO] +- org.springframework:spring-web:jar:4.0.1.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:4.0.1.RELEASE:compile
[INFO] | | - aopalliance:aopalliance:jar:1.0:compile
[INFO] | +- org.springframework:spring-beans:jar:4.0.1.RELEASE:compile
[INFO] | +- org.springframework:spring-context:jar:4.0.1.RELEASE:compile
[INFO] | | - org.springframework:spring-expression:jar:4.0.1.RELEASE:compile
[INFO] | - org.springframework:spring-core:jar:4.0.1.RELEASE:compile
[INFO] +- commons-fileupload:commons-fileupload:jar:1.2.2:compile
[INFO] +- bsf:bsf:jar:2.4.0:compile
[INFO] +- org.codehaus.groovy:groovy-bsf:jar:2.1.7:compile
[INFO] | - org.codehaus.groovy:groovy:jar:2.1.7:compile
[INFO] | +- antlr:antlr:jar:2.7.7:compile
[INFO] | +- org.ow2.asm:asm-tree:jar:4.0:compile
[INFO] | +- org.ow2.asm:asm-commons:jar:4.0:compile
[INFO] | +- org.ow2.asm:asm:jar:4.0:compile
[INFO] | +- org.ow2.asm:asm-util:jar:4.0:compile
[INFO] | - org.ow2.asm:asm-analysis:jar:4.0:compile
[INFO] - org.apache.tomcat:tomcat-jdbc:jar:7.0.55:compile
[INFO] - org.apache.tomcat:tomcat-juli:jar:7.0.55:compile

Thank you very much.
Best,
Coco

@HelloCoCooo
Copy link
Contributor Author

HelloCoCooo commented Apr 7, 2019

Code snippet of <org.apache.commons.logging.LogFactory: org.apache.commons.logging.LogFactory getFactory()> in commons-logging:commons-logging:jar:1.1.3 (loaded version):

02
.......

Code snippet of <org.apache.commons.logging.LogFactory: org.apache.commons.logging.LogFactory getFactory()> in org.slf4j:jcl-over-slf4j:jar:1.5.10:runtime
(shadowed but expected to invoke method):
01

As a result, these conflicting method included in org.slf4j:jcl-over-slf4j:jar:1.5.10:runtime deals with different cases, which changes the control flows and data flows. So being forced to use these methods in commons-logging:commons-logging:jar:1.1.3 may lead to inconsisitent semantic behaviors.

Using the following test case to run on these two versions of methods separately starting from the entry method Log t = (Log) field.get(httpClient); in your project, then we can find that the return values of the entry method is assigned different values.
Testcaseforgrouponodo.txt

Please check whether the changes of this variable value will affect your semantic behaviors.

@djrenfro
Copy link
Collaborator

djrenfro commented Apr 8, 2019

@HelloCoCooo yes, feel free to make a PR from your fork. Thanks for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants