others-how to solve `java.lang.NoSuchMethodError: No static method encodeBase64URLSafeString` that caused by conflict between imported library and our environment?

1. Purpose

In this post, I will try to solve the following error when trying to access the encodeBase64URLSafeString method in commons-codec:

2022-07-03 10:47:34.181 22021-22583/? E/AndroidRuntime: FATAL EXCEPTION: Thread-20
    Process: com.bswen.app, PID: 22021
    java.lang.NoSuchMethodError: No static method encodeBase64URLSafeString([B)Ljava/lang/String; in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
        at com.bswen.app3.ui.misc.GoogleSigninActivity.a(SourceFile:31)
        at com.bswen.app3.ui.misc.GoogleSigninActivity$b$a.run(SourceFile:1)
        at java.lang.Thread.run(Thread.java:764)

The code that caused the above problem:

byte[] rawMessageBytes = buffer.toByteArray();
String encodedEmail = Base64.encodeBase64URLSafeString(rawMessageBytes);

The problem occurred because there is a conflict between commons-codec and org.apache.http.legacy.boot.jar in android system. They both have the class named org.apache.commons.codec.binary.Base64, but they have different versions.



2. Solution

2.1 Solution #1

Because it can not find the method, so we can just create one:

private static String encodeBase64URLSafeString(byte[] binaryData) {
    return android.util.Base64.encodeToString(binaryData, Base64.URL_SAFE);
}

2.2 Solution #2

Or we can use jarjar tool to transplant the commons-codec library to a custom library for us.

Jar Jar Links is a utility that makes it easy to repackage Java libraries and embed them into your own distribution. This is useful for two reasons: You can easily ship a single jar file with no external dependencies.

To simplify ,jarjar allow us to change the package of an existing library to a customized package name, then we can avoid the conflication problem when importing library to our project.

To use jarjar, we first need to create a rules.txt,which tells jarjar how to change the library:

Create a rules.txt as follows:

rule pattern result
zap pattern
rule org.apache.commons.codec.** [email protected]

The above rule tells jarjar to change the package name of commons-codec library from org.apache.commons.codec to our customized name com.bswen.codec

then create new jar with jarjar

java -jar jarjar-1.4.jar process ./rules.txt commons-codec-1.6.jar bswen-codec-1.6.jar

then you get this:

➜  commons_codec ll
total 5448
[email protected] 1 bswen  staff   1.2M Jul  8 21:26 commons-codec-1.6-bin.zip
[email protected] 1 bswen  staff   227K Jul  8 21:29 commons-codec-1.6.jar
[email protected] 1 bswen  staff   118K Jul  8 21:24 jarjar-1.4.jar
-rw-r--r--  1 bswen  staff   225K Jul  8 21:38 bswen-codec-1.6.jar
-rw-r--r--  1 bswen  staff    88B Jul  8 21:38 rules.txt

check the packages inside the jar:

➜  commons_codec java -jar jarjar-1.4.jar strings bswen-codec-1.6.jar
com.bswen.codec.net.Utils
    44: "Invalid URL encoding: not a valid digit (radix 16): "
com.bswen.codec.net.URLCodec
    103: "UTF-8"
    179: "Invalid URL encoding: "
    312: "Objects of type "
    312: " cannot be URL encoded"
    337: "Objects of type "
    337: " cannot be URL decoded"
com.bswen.codec.net.RFC1522Codec
    "?="
    "=?"
    88: "=?"
    95: "?="
    118: "=?"
    118: "?="
    119: "RFC 1522 violation: malformed encoded content"
    125: "RFC 1522 violation: charset token not found"
    129: "RFC 1522 violation: charset not specified"
    134: "RFC 1522 violation: encoding token not found"
    138: "This codec cannot decode "
    138: " encoded content"
com.bswen.codec.net.QuotedPrintableCodec
    96: "UTF-8"
    190: "Invalid quoted-printable encoding"
    324: "Objects of type "
    324: " cannot be quoted-printable encoded"
    349: "Objects of type "
    349: " cannot be quoted-printable decoded"
com.bswen.codec.net.QCodec
...

You can see that the package name has been successfully changed to com.bswen.codec..., then we can just import the new pacakge com.bswen.codec and use it to do base64 encoding and decoding.



3. Summary

In this post, I demonstrated how to solve the java.lang.NoSuchMethodError when trying to import a library into our project , the problem is caused by the confliction between the imported library and our runtime environment, to solve this problem, we can create the missing method or just transplant the library into our customized package . That’s it, thanks for your reading.

-->