-
Notifications
You must be signed in to change notification settings - Fork 71
Description
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
- 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:
- 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
- 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
-
build java-algorand-sdk project with maven to create a new jar algosdk-1.10.0_tim.jar
-
Add that jar to our project. deploy. test
There are other better solutions
- 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)
- 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)