ProGuard and Gson on Android (ClassCastException)
Solution 1
For the latest version of the recommended proguard configuraiton file, please see the gson supplied android proguard example at: https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
Solution 2
These settings in the config worked for me in one of my apps:
# Add the gson class
-keep public class com.google.gson
# Add any classes the interact with gson
-keep class com.someapp.android.models.ChatModel { *; }
-keep class com.someapp.android.models.FeedModel { *; }
# Add the path to the jar
-libraryjars /Users/someuser/Documents/workspace/someapp/lib/gson-1.7.1.jar
Hopefully this helps you out.
Solution 3
Applying the changes found in the Android example in the Gson project worked for me
The lines needed were:
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
# and keeping the classes that will be serialized/deserialized
Solution 4
I know the original question was resolved by taking a different approach, but I was having a very similar issue using flexjson and Proguard on Android, and I've solved it, in case anyone runs into it themselves.
When converting back from JSON to my value object which included some ArrayLists, I would get the same ClassCastException. I got it to work by basically having obfuscation enabled but turning all parts of obfuscation off (-keep everything, -keepclassmembers everything and -keepattributes everything) and then working backwards by enabling things a bit at a time.
The result; keeping the entire flexjson library:
-keep class flexjson**
--keepclassmembers class flexjson** {
*;
}
and keeping the Signature and Annotation attribute:
-keepattributes Signature, *Annotation*
I was able to use the flexjson library without incident after that in a proguarded, release version of my app.
Solution 5
I was getting errors for Model classes with proguard If you look at
GSON Proguard you will find a line
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
replace com.google.gson.examples.android.model.
with your model
package likewise in my case i replaced it with -keep class com.consumer.myProject.model.** { *; }
rest I copied as such
Jesse
Updated on January 26, 2021Comments
-
Jesse over 3 years
I am having a hell of a time with Gson and ProGuard. I have a simple object and when I parse tojson, save to sqllite and read back from the database in order to load the json back to my object, I get a java.lang.classcastexception. If I dont use ProGuard, everthing works fine.
I have verified that the json string being sent to and gotten from the database is the same. The exception is not thrown when it converts from json, but rather when I try to access the object.
Here is my simple object:
public class ScanLog extends ArrayList<SingleFrame> { private static final long serialVersionUID = 1L; public ScanLog() { } } public final class SingleFrame { public int Position; public int Time; public Map<Integer,String> MainDataMap; public Map<Integer,String> DataMap; public SingleFrame(int position, int time, Map<Integer,String> mainDataMap, Map<Integer,String> dataMap) { this.Position = position; this.Time = time; this.MainDataMap = mainDataMap; this.DataMap = dataMap; } }
All other aspects of my app are fine, but something with proguard is causing this to happen....Ive tried all kinds of -keep commands in the proguard.cfg but I am not sure what Im doing is right.
EDIT - ADDING PROGUARD.CFG
-dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -dontshrink -dontoptimize -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService #keep all classes that might be used in XML layouts -keep public class * extends android.view.View -keep public class * extends android.app.Fragment -keep public class * extends android.support.v4.Fragment #keep all classes -keep public class *{ public protected *; } #keep all public and protected methods that could be used by java reflection -keepclassmembernames class * { public protected <methods>; } -keepclasseswithmembernames class * { native <methods>; } -keep public class org.scanner.scanlog.SingleFrame -keepclassmembers class org.scanner.scanlog.ScanLog { private <fields>; public <fields>; } -keepclassmembers class org.scanner.scanlog.SingleFrame { private <fields>; public <fields>; } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -dontwarn **CompatHoneycomb -dontwarn org.htmlcleaner.* #-keep class android.support.v4.** { *; }
EDIT - Okay I got ACRA set up successfully in my app, pretty awesome feature! Here is the stack trace:
java.lang.ClassCastException: java.lang.Object at org.scanner.activity.ReaderMainActivity.AdvanceScanLog(SourceFile:1499) at org.scanner.activity.r.onProgressChanged(SourceFile:271) at android.widget.SeekBar.onProgressRefresh(SeekBar.java:89) at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:507) at android.widget.ProgressBar.refreshProgress(ProgressBar.java:516) at android.widget.ProgressBar.setProgress(ProgressBar.java:565) at android.widget.AbsSeekBar.trackTouchEvent(AbsSeekBar.java:337) at android.widget.AbsSeekBar.onTouchEvent(AbsSeekBar.java:292) at android.view.View.dispatchTouchEvent(View.java:3932) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157) at android.app.Activity.dispatchTouchEvent(Activity.java:2181) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759) at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2336) at android.view.ViewRoot.handleMessage(ViewRoot.java:1976) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:143) at android.app.ActivityThread.main(ActivityThread.java:4263) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) at dalvik.system.NativeStart.main(Native Method)
-
Jesse almost 13 yearsThanks,I checked my seeds file and it has the following: 'org.scanner.scanlog.SingleFrame org.scanner.scanlog.SingleFrame: int Position org.scanner.scanlog.SingleFrame: int Time org.scanner.scanlog.SingleFrame: java.util.Map MainDataMap org.scanner.scanlog.SingleFrame: java.util.Map DataMap org.scanner.scanlog.SingleFrame: SingleFrame(int,int,java.util.Map,java.util.Map)'
-
Jesse almost 13 yearsMaybe it has something to do with the obfuscation of java.util.Map? Not sure what to do about it though?
-
blindstuff almost 13 yearsThis worked for me, but I had to add:
-keepattributes Signature
-
Murat about 12 yearsThe lines you mentioned was not enough for me but i applied the things in the example you provied and worked for me. Thank you.
-
Trinimon about 11 years"Add any classes the interact that interact with gson" that did it for me, thanks!
-
Crake almost 11 yearsgson uses reflection at runtime to dynamically map the json into classes by string matching the properties. This will never work with obfuscated sources, since model.name is replaced with a.b by Proguard. It has less to do with GSON specifically and more to do with any library that uses reflection in this manner. In order to use proguard with GSON, you need to exclude the classes you are serializing / deserializing from obfuscation in the proguard config file.
-
Jonik over 10 years+1. If using e.g.
@SerializedName
annotation from Gson in your model classes,-keepattributes *Annotation*
is necessary! -
umesh about 10 years@jerry # Add any classes the interact with gson, it works for me but when i applied reverse engg on apk, i got all the model classes with not change in members, i am able to decompile all model, it breaks the security purpose, isn't there any other option ?
-
Matt Accola about 10 years@blindstuff You shouldn't add -libraryjars. In this document, proguard.sourceforge.net/index.html#manual/troubleshooting.html, it says "You should never explicitly specify the input jars yourself (with -injars or -libraryjars), since you'll then get duplicate definitions."
-
Dmitry Zaytsev over 9 yearsWelcome to 2014 where 577Kb and 260Kb are equally nothing.
-
Shajeel Afzal over 9 yearsBut i am getting the following exception with Exported apk with ProGuard:
Caused by: java.lang.AbstractMethodError: abstract method "void com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$a.a(com.google.gson.stream.JsonWriter, java.lang.Object)" at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.Gson.toJson(Gson.java:546) at com.google.gson.Gson.toJson(Gson.java:525) at com.google.gson.Gson.toJson(Gson.java:480) at com.google.gson.Gson.toJson(Gson.java:460)
-
Shajeel Afzal over 9 years@jonik i am using
SerializeName
and i have added-keepattributes *Annotation*
statement but still i am getting:java.lang.AbstractMethodError: abstract method "void com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$a.a(com.google.gson.stream.JsonWriter, java.lang.Object)" at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.Gson.toJson(Gson.java:546
-
Shajeel Afzal over 9 yearsI think if someone wants to keep all classes in the Models package he should write:
-keep class com.someapp.android.models.** { *; }