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

Using the unexpected method, due to dependency conflicts on com.squareup.okhttp3:okhttp #12

Closed
HelloCoCooo opened this issue Sep 17, 2020 · 3 comments

Comments

@HelloCoCooo
Copy link
Contributor

HelloCoCooo commented Sep 17, 2020

Issue description

Hi, in SmartIM/smartqq, there are mulptiple versions of library com.squareup.okhttp3:okhttp. However, according to Maven's dependency management strategy: "first declaration wins", only com.squareup.okhttp3:okhttp:3.8.1 can be loaded, and com.squareup.okhttp3:okhttp:3.14.4 will be shadowed.

In total, there are 11 conflicting API pairs between these two library version.

Your project expects to reference the method <okhttp3.Handshake: toString()Ljava/lang/String;> via com.qiniu:qiniu-java-sdk7.2.29, which is included in the shaded version com.squareup.okhttp3:okhttp:3.14.4 (original dependency path). However, this method is missing in the actual loaded versioncom.squareup.okhttp3:okhttp:3.8.1. Surprisingly, it will not cause NoSuchMethodError at rumtime.
By further analyzing, I found that the caller(com.qiniu:qiniu-java-sdk) would invoke the method java.lang.Object.toString() defined in okhttp3.Handshake's superclass , due to dynamic binding mechanism (actual dependency path).

However, methods java.lang.Object.toString() and <okhttp3.Handshake: toString()Ljava/lang/String;> have different implementations, which will lead to buggy behaviors-----

Code snippet of <okhttp3.Handshake: toString()Ljava/lang/String;> in com.squareup.okhttp3:okhttp:3.14.4 (shadowed but expected to invoke):

@Override 
public String toString() {
    return "Handshake{"
        + "tlsVersion="
        + tlsVersion
        + " cipherSuite="
        + cipherSuite
        + " peerCertificates="
        + names(peerCertificates)
        + " localCertificates="
        + names(localCertificates)
        + '}';
  }

Code snippet of <toString()Ljava/lang/String;> in com.squareup.okhttp3:okhttp:3.8.1 (loaded version):

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

4D8897DF-4AE0-48BD-B718-DD740947E5A4

Actual dependency path:

<com.scienjus.smartqq.QNUploader: upload(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/qiniu/common/Zone;)Lcom/scienjus/smartqq/QNUploader$UploadInfo;> /home/wwww/wangSensor/unzip/SmartIM-master/smartqq/target/classes
<com.qiniu.storage.UploadManager: put(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/qiniu/http/Response;> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<com.qiniu.storage.UploadManager: put(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/qiniu/util/StringMap;Ljava/lang/String;Z)Lcom/qiniu/http/Response;> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<com.qiniu.storage.UploadManager: put(Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Lcom/qiniu/util/StringMap;Ljava/lang/String;Z)Lcom/qiniu/http/Response;> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<com.qiniu.storage.UploadManager: filterParam(Lcom/qiniu/util/StringMap;)Lcom/qiniu/util/StringMap;> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<com.qiniu.util.StringMap: forEach(Lcom/qiniu/util/StringMap$Consumer;)V> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<com.qiniu.util.StringMap$1: accept(Ljava/lang/String;Ljava/lang/Object;)V> /home/wwww/.m2/repository/com/qiniu/qiniu-java-sdk/7.2.29/qiniu-java-sdk-7.2.29.jar
<Java.lang.Object: toString()Ljava/lang/String;>

The detailed informantion of the remaining 10 conflicting API pairs can be found in the following attachment.
11 conflicting API pairs in project smartqq.txt

Dependency tree--

[INFO] cn.ieclipse.smartim:smartqq:jar:0.0.1
[INFO] +- cn.ieclipse.smartim:core:jar:0.0.1:compile
[INFO] | +- (org.slf4j:slf4j-api:jar:1.7.25:compile - omitted for duplicate)
[INFO] | +- (ch.qos.logback:logback-classic:jar:1.2.3:compile - omitted for duplicate)
[INFO] | +- (com.squareup.okhttp3:okhttp:jar:3.8.1:compile - omitted for duplicate)
[INFO] | +- (com.google.code.gson:gson:jar:2.8.0:compile - omitted for duplicate)
[INFO] | - (com.github.jamling:JavaUtils:jar:933b1c6551:compile - omitted for duplicate)
[INFO] +- com.qiniu:qiniu-java-sdk:jar:7.2.29:compile
[INFO] | +- (com.squareup.okhttp3:okhttp:jar:3.14.4:runtime - omitted for conflict with 3.8.1)
[INFO] | - (com.google.code.gson:gson:jar:2.8.5:runtime - omitted for conflict with 2.8.0)
[INFO] +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | +- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | - (org.slf4j:slf4j-api:jar:1.7.25:compile - omitted for duplicate)
[INFO] +- com.squareup.okhttp3:okhttp:jar:3.8.1:compile
[INFO] | - com.squareup.okio:okio:jar:1.13.0:compile
[INFO] +- junit:junit:jar:4.12:test
[INFO] | - org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- com.google.code.gson:gson:jar:2.8.0:compile
[INFO] - com.github.jamling:JavaUtils:jar:933b1c6551:compile
[INFO] +- com.github.jamling.JavaUtils:core:jar:933b1c6551:compile
[INFO] | - (org.slf4j:slf4j-api:jar:1.7.21:runtime - omitted for conflict with 1.7.25)
[INFO] +- com.github.jamling.JavaUtils:jee:jar:933b1c6551:compile
[INFO] | +- (org.slf4j:slf4j-api:jar:1.7.21:runtime - omitted for conflict with 1.7.25)
[INFO] | +- javax.servlet:javax.servlet-api:jar:3.1.0:runtime
[INFO] | - (com.github.jamling.JavaUtils:core:jar:933b1c6551:runtime - omitted for duplicate)
[INFO] +- com.github.jamling.JavaUtils:playground:jar:933b1c6551:compile
[INFO] | - (org.slf4j:slf4j-api:jar:1.7.21:runtime - omitted for conflict with 1.7.25)
[INFO] - com.github.jamling.JavaUtils:swing:jar:933b1c6551:compile
[INFO] - (org.slf4j:slf4j-api:jar:1.7.21:runtime - omitted for conflict with 1.7.25)

Suggested solutions:

Solution1: Remove the dependency com.squareup.okhttp3:okhttp:3.8.1.

Solution2: Declare version com.squareup.okhttp3:okhttp:3.14.4 as a direct dependency.

Thanks.
Best regards,
Coco

@HelloCoCooo
Copy link
Contributor Author

Executing the following test case on com.squareup.okhttp3:okhttp:3.14.4 and 3.8.1 separately, the risky method <okhttp3.Handshake: toString()Ljava/lang/String;> will get different return values:

@Test(timeout = 4000)
    public void test01()  throws Throwable  {
        TlsVersion tlsVersion0 = TlsVersion.TLS_1_1;
        CipherSuite cipherSuite0 = CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256;
        LinkedList<Certificate> linkedList0 = new LinkedList<Certificate>();
        Handshake handshake0 = Handshake.get(tlsVersion0, cipherSuite0, (List<Certificate>) linkedList0, (List<Certificate>) linkedList0);
        Assert.assertEquals("Handshake{tlsVersion=TLS_1_1 cipherSuite=TLS_DH_anon_WITH_AES_128_CBC_SHA256 peerCertificates=[] localCertificates=[]}", handshake0.toString());
    }

Output results:

[Handshake{tlsVersion=TLS_1_1 cipherSuite=TLS_DH_anon_WITH_AES_128_CBC_SHA256 peerCertificates=[] localCertificates=[]}]   //On **com.squareup.okhttp3:okhttp:3.14.4**

[okhttp3.Handshake@75526d62]    //On **com.squareup.okhttp3:okhttp:3.8.1**

Variable b (defined in class com.qiniu.util.StringMap of library com.qiniu:qiniu-java-sdk:jar:7.2.29) is assigned by the return value of method <okhttp3.Handshake: toString()Ljava/lang/String;>.

As such, b value would be changed when the client project references com.squareup.okhttp3:okhttp:3.8.1 (compared with the shadowed but expected version 3.14.4), which could affect program semantic behaviors.

public String formString() {
        final StringBuilder b = new StringBuilder();
        forEach(new Consumer() {
            private boolean notStart = false;

            @Override
            public void accept(String key, Object value) {
                if (notStart) {
                    b.append("&");
                }
                try {
                    b.append(URLEncoder.encode(key, "UTF-8")).append('=')
                            .append(URLEncoder.encode(value.toString(), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new AssertionError(e);
                }
                notStart = true;
            }
        });
        return b.toString();
    }

@HelloCoCooo
Copy link
Contributor Author

@Jamling Could please help me check this issue?
May I pull a request to fix it?
Thanks again.

@Jamling
Copy link
Owner

Jamling commented Nov 1, 2020

Because the SmartQQ is out of service since 2019.1.1, I have no plan to fix the issue, you can pull a request to fix it

HelloCoCooo added a commit to HelloCoCooo/SmartIM that referenced this issue Nov 2, 2020
Fix the dependency conflict issue Jamling#12 by Solution2 Declare version com.squareup.okhttp3:okhttp:3.14.4 as a direct dependency.
Jamling pushed a commit that referenced this issue Nov 2, 2020
Fix the dependency conflict issue #12 by Solution2 Declare version com.squareup.okhttp3:okhttp:3.14.4 as a direct dependency.
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