I am trying to use the library DigestUtils in Android 2.3.1 using JDK 1.6, however I get the following error when executing the app:
Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.shaHex
Here you have the stacktrace:
02-03 10:25:45.153: I/dalvikvm(1230): Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.shaHex
02-03 10:25:45.153: W/dalvikvm(1230): VFY: unable to resolve static method 329: Lorg/apache/commons/codec/binary/Hex;.encodeHexString ([B)Ljava/lang/String;
02-03 10:25:45.153: D/dalvikvm(1230): VFY: replacing opcode 0x71 at 0x0004
02-03 10:25:45.153: D/dalvikvm(1230): VFY: dead code 0x0007-0008 in Lorg/apache/commons/codec/digest/DigestUtils;.shaHex ([B)Ljava/lang/String;
02-03 10:25:45.163: D/AndroidRuntime(1230): Shutting down VM
02-03 10:25:45.163: W/dalvikvm(1230): threadid=1: thread exiting with uncaught exception (group=0x40015560)
02-03 10:25:45.173: E/AndroidRuntime(1230): FATAL EXCEPTION: main
02-03 10:25:45.173: E/AndroidRuntime(1230): java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString
02-03 10:25:45.173: E/AndroidRuntime(1230): at org.apache.commons.codec.digest.DigestUtils.md5Hex(DigestUtils.java:226)
02-03 10:25:45.173: E/AndroidRuntime(1230): at com.caumons.trainingdininghall.ConnectionProfileActivity.onCreate(ConnectionProfileActivity.java:20)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.os.Handler.dispatchMessage(Handler.java:99)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.os.Looper.loop(Looper.java:123)
02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.main(ActivityThread.java:3647)
02-03 10:25:45.173: E/AndroidRuntime(1230): at java.lang.reflect.Method.invokeNative(Native Method)
02-03 10:25:45.173: E/AndroidRuntime(1230): at java.lang.reflect.Method.invoke(Method.java:507)
02-03 10:25:45.173: E/AndroidRuntime(1230): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-03 10:25:45.173: E/AndroidRuntime(1230): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-03 10:25:45.173: E/AndroidRuntime(1230): at dalvik.system.NativeStart.main(Native Method)
The line of code which causes the exception is:
String hash = DigestUtils.shaHex("textToHash");
I have executed the same code in a Java class outside Android and it works! So, I do not know why when working with Android it does not work... I put the libraty inside a new libs/ folder in my app and updated the BuildPath to use it. If I try to use md5 instead of sha1 I get the same exception. Any help would be appreciated! Thank you.
UPDATE:
As this is a very active question, I've changed the accepted answer in favour of @DA25, as his solution is straightforward and the high number of upvotes prove that it works.
Finally I get the answer and it works well. As described in No such method error in Apache codec for another type of encrypt (Base64) I tried to reproduce the same issue and I get exactly the same error. So I was in the case of the question attached. As they say, it seems to be an internal name collision with the package name
org.apache.commons.codec
and as stated by @Don I changed it tocom.apache.commons.codec
and worked fine! How I did it?I downloaded the source code and changed the 3 directories
org
tocom
. I also replaced all the occurrences of the package name in the files where they appear and also changed the references in the docs tocom/apache/commons/codec/
. (Do not try to remane them manually or you will spend the hole day). Then I compiled the library and generated the jar with Ant, which I calledcommons-codec-1.6-android.jar
. I put the jar in thelibs/
folder of my Android app and added it to the buildpath. Also, I attached the sources as the folder which contains all the files. So now I have the library ready to use with Android!Hope that it helps someone else!
I ran into the same issue trying to use DigestUtils in my Android app. This was the best answer I could find by searching, but I was reluctant to rebuild the .jar file with the namespace changed. After spending some time on this issue, I found an easier way to solve the problem for my case. The problem statement for my code was
Replace this statement with the following and it will work:
Similarly, for shaHex exampl, you can change it to
This works because even though Android does not have encodeHexString(), it does have encodeHex(). Hope this would help others who run into the same issue.
Thanks @DA25
This is working fine for me
I have add dependency
ref: http://mvnrepository.com/artifact/commons-codec/commons-codec/1.9
my function
Add method
Since there's no clear answer for the root cause of this problem, I'd like to clarify what's happening here.
Why the NoSuchMethodError is thrown in the first place?
According to exception stack trace, the line that causes the fault is 226 in
DigestUtils#md5hex
method. Let's see what we have there (I'm assuming you have used version 1.4, since this is the only release whereHex#encodeHexString
method is being invoked in line 226):The exception says
java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString
. Let's understand why.First of all, Android framework already includes the
Commons Codec
library (except theDigestUtils
class). Yes, it is not exposed as part of theAndroid SDK
and you cannot use it directly. But you still want to use it. So what you do? You addCommons Codec
library as part of your application. The compiler doesn't complain - from his point of view everything was fine.But what happens at runtime? Let's follow your exception stack trace:
First, you're calling
DigestUtils#md5Hex
from your Activity'sonCreate
method. As I wrote above, the framework doesn't include that class, soDigestUtils
(fromCommons Codec
version 1.4) is loaded from your dex.Next,
md5hex
method tries to invokeHex#encodeHexString
method.Hex
class is part of theCommons Codec
library that included in framework. The thing is that its version is 1.3 (ancient release from July 2004).Hex
class exists in boot classpath, which means that the runtime will always favor it instead of theHex
class that packaged inside your dex. You can see warnings about it in your application logs when you start your app (with Dalvik runtime):Hex#encodeHexString method was introduced in version 1.4 of
Commons Codec
library and therefore it doesn't exist in framework'sHex
class. The runtime can't find this method and thus throwsNoSuchMethodError
exception.Why the accepted answer's solution works?
First,
DigestUtils#md5
method is called. As I already stated,DigestUtils
class that will be used is the one that packaged in your dex. This method doesn't use any otherCommons Codec
classes, so no problem with it.Next,
Hex#encodeHex
will be called. TheHex
class that will be used is the framework's one (version 1.3). TheencodeHex
method (that takes a single parameter - byte array) exists in version 1.3 ofCommons Codec
library, and therefore this code will work fine.What would I suggest?
My suggested solution is to rename the classes namespace/package. By doing so I'm explicitly specifying which code is going to execute, and prevent bizarre behavior that may occur because of versioning issues.
You can do it manually (as Caumons wrote in his answer), or automatically with jarjar tool.
See this issue summary and tips for using
jarjar
in my blogpost.For me proguard removed the class during obfuscation .Add this to your Proguard rules.
Here's the method I was using of apache package.