Skip to content

SDK jar not compatible with old Android Runtimes #271

@timmolter

Description

@timmolter

Subject of the issue

Basically, the old 4.x android runtime comes with an ancient org.apache.commons.codec jar and during class loading on startup there is a Base64 class with the same namespace in both that ancient jar and the new one included in this project's dependency list. We get a java.lang.NoSuchMethodError exception when we call Base64#decode(String). Our compiler sees the method because it's on our compiler's classpath, but the runtime doesn't see it because it loaded the ancient Base64 class, WITHOUT THAT METHOD.

This is a well-known issue.

https://stackoverflow.com/a/29102701
https://stackoverflow.com/a/5163910

Your environment

irrelevant to problem, but we're running the latest versions

Steps to reproduce

  1. Run any app using the latest SDK jar as a dependency on an Android 4 phone.

Expected behaviour

no crashes

Actual behaviour

It crashes with exception:

Caused by: java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.decode(Ljava/lang/String;)[B
    at com.algorand.algosdk.util.Encoder.decodeFromBase64(Encoder.java:165)
    at com.algorand.algosdk.v2.client.model.Transaction.genesisHash(Transaction.java:124)
    at java.lang.reflect.Method.internalInvoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:591)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:141)

My (temporary) solution (hack) to prove what the problem was:

  1. use a tool called jarjar (https://stackoverflow.com/a/33592560) to clone the commons-codec-1.15.jar and rename it algorandv2-commons-codec-1.15.jar while also renaming all the class namespaces internally from org.apache.commons.codec.** to algorandv2.org.apache.commons.codec.**
java -jar jarjar-1.4.jar process myrules.txt commons-codec-1.15.jar algorandv2-commons-codec-1.15.jar                                                      
  1. clone the algo sdk repo and update all import statements referencing org.apache.commons.codec.** to algorandv2.org.apache.commons.codec.** and adding my custom algorandv2-commons-codec-1.15.jar to their project.

Put in in your local maven repo (https://stackoverflow.com/a/42804029):

mvn install:install-file -DgroupId=algorandv2 -DartifactId=algorandv2-commons-codec -Dversion=1.15 -Dpackaging=jar -Dfile=algorandv2-commons-codec-1.15.jar

Here's my fork with the updates: https://github.com/timmolter/java-algorand-sdk/tree/Charset

  1. build java-algorand-sdk project with maven to create a new jar algosdk-1.10.0_tim.jar

  2. Add that jar to our project. deploy. test

There are other better solutions

  1. Use BouncyCastle's Base64 class. I tried to do this, but some unit tests failed. So you guys would have to do it and carefully see what's going on there. (Seems like the most elegant solution)
  2. Copy-paste commons.codec's Base64 code into your source code, renaming the namespace (I could create a PR for this if you'd like)

Metadata

Metadata

Assignees

No one assigned

    Labels

    new-bugBug report that needs triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions