Proguard - PersistenceException: Constructor not matched for class - android

I am using retrofit2.0 in my app with simpleframework.xml library.
The problem is when I run the app without proguard it works fine however when I run proguard I get the following Error in logs.
E/ERROR: java.lang.RuntimeException: org.simpleframework.xml.core.PersistenceException: Constructor not matched for class A
The class A has no/default constructor which should work. Still I added a No Argument Constructor. But that didn't rectify the issue.
Class A
#Root(name = "data",strict = false)
public class A {
#Element(name = "baseurl",required = false)
private String baseURl;
#Element(name = "country_code")
private String country_code;
// Setters and getters
}
As you can see there is no constructor (Adding the default empty constructor keeps the issue). So default No Argument Constructor should work just as well. However I tried with the following constructor and this removes the error.
public A(#ELement(name = "baseurl") String baseUrl,
#Element(name = "country_code") String country_code) { // Add all the elements from the xml in the constructor i.e. if a new element is added a new constructor would have to be written.
baseURl = baseUrl;
this.country_code = country_code;
}
But I have too many files to change if I want to do it this way. Besides a constructor requiring all the values mapped shouldn't be required. I have quite a few classes which host more than 50 member variables (I simplified the example class to include only two member variables). This class contains about 30 and code would've been simply too long to post here.
The thing is I have loads of classes working on the assumption of No Argument constructor for each class.
Simply adding constructors for all is not feasible.
My proguard-rules.pro (with only relevant lib obfuscation rules).
#-keepattributes *Annotation*
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-dontwarn com.bea.xml.stream.**
-dontwarn org.simpleframework.xml.stream.**
-keep class org.simpleframework.xml.**{ *; }
-keepclassmembers,allowobfuscation class * {
#org.simpleframework.xml.* <fields>;
#org.simpleframework.xml.* <init>(...);
}
It might be worth noting that before this Error I was getting
E/ERROR: java.lang.RuntimeException: org.simpleframework.xml.core.ElementException: Element 'version' does not have a match in class A at line 1
Solved that by adding 'name' argument in #Element Annotation. So one of the reasons I'm reluctant to change all the files is what if another Error creeps up.
EDIT 1:
So after 2 days of searching for a solution I gave up and finally added constructors to all the classes. The thing is the library calls constructor for only the available xml-tags. Say for the above class A if only country_code was available in the xml
<xml>
<data>
<country_code>PK</country_code>
</data>
</xml>
Then I'd need a constructor with only one argument of country_code to make it work
public A(#Element(name = "country_code") String country_code) {
this.country_code = country_code;
}
Which makes the found solution unusable.
EDIT 2:
Found a workaround! Keeping the POJO classes in the proguard rules fixes this error. But I would rather not keep these classes.
And so I'm keeping this question open at-least for now or until someone can tell me why I should keep these files.

I guess that your problem is that you are not keeping any attributes and that obviously depends in which attributes you are using. In my case, this is how I dealt with it, let me know if it works for you:
## https://square.github.io/retrofit/ ##
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
#retrofit2.http.* <methods>;
}
## Simple XML ##
-dontwarn org.simpleframework.xml.stream.**
-keep public class org.simpleframework.** { *; }
-keep class org.simpleframework.xml.** { *; }
-keep class org.simpleframework.xml.core.** { *; }
-keep class org.simpleframework.xml.util.** { *; }
-keepattributes ElementList, Root, *Annotation*
-keepclassmembers class * {
#org.simpleframework.xml.* *;
}

try adding these below lines in your proguard file. It should solve your problem
-dontnote retrofit2.Platform
-keepattributes Signature
-keepattributes Exceptions
and remove these below lines
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }

Related

Android apk not connecting to Azure server after using proguard

I have been looking to a solution to this problem, i have tried many proguard configurations without success.
The app runs perfectly until I make the release version with proguard.
I am getting the error:
"java.lang.IllegalArgumentException:The class representing the mobile serviceTable must have a single id property defined" while assigning the class
I belive that is caused by the class of the table that i am trying to reach, having its variable 'id' name changed.
I have the folowing:
public class User {
public String id;
public String nickname;
public String phone;
}
and the connection is made with:
mClient.getTable(User.class).where().field("nickname")
.eq(nick).execute(new TableQueryCallback<User>() {....
the proguard config file is:
-keep class com.microsoft.azure.storage.table.** { *; }
-dontwarn com.fasterxml.jackson.core**
-keep class com.microsoft.windowsazure.mobileservices.** { *; }
-dontwarn android.os.**
-dontwarn com.microsoft.windowsazure.mobileservices.RequestAsyncTask
##---------------from here is the part that i have modified a lot of times -
-keepattributes Signature
-keepattributes *Annotation*
-keep public class com.company.app.User.** { *; }
-keepclassmembers public class com.company.app.User.** { *; }
I have tried many modifications for hours without success.
I followed this and this among many others.
Can you please help me?
Thanks
EDIT: solved. Just remove the .** after User in the proguard file. Leave it like this:
-keep public class com.company.app.User { *; }
-keepclassmembers public class com.company.app.User { *; }
solved. Just remove the .** after User in the proguard file. Leave it like this:
-keep public class com.company.app.User { *; }
-keepclassmembers public class com.company.app.User { *; }

android - how to keep enum from proguard

In my proguard, I have the following to keep public enums from being obfuscated.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
My question is, does this also keep the public enum Currency in a class like this?
public class Foo {
public enum **Currency** {PENNY, NICKLE, DIME, QUARTER};
...
}
If not, what do I have to add separately?
Adding the following doesn't seem to help.
-keepattributes InnerClasses
Any advice? Thanks
You could try
-keep public enum com.stuff.TheEnclosingClass$** {
**[] $VALUES;
public *;
}
As shown on this answer Proguard won't keep a class member's enums
Just don't forget to put
-keepattributes InnerClasses
Can you try to tell proguard to keep the specific class:
-keep class com.xxx.Foo { *; }
The option -keepclassmembers only keeps the class members; in this case the methods values() and valueOf(String) of all enum classes. The wild card * also matches internal classes.
If you for some reason want to preserve the inner class with its original name, you can specify:
-keep class somepackage.Foo$Currency
That should only be necessary if your application accesses the class through reflection.
If you want to safe enum names and all fields, methods for it:
-keep enum * { *; }

ProGuard - org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type

I have an Android-based application which is connecting to the Google App Engine using Rest services, the app works perfectly until it is obfuscated through ProGuard prior to release.
The error reported in LogCat when running the obfuscated app is:
Unable to convert a [application/json,UTF-8] representation into an object of
class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found
for type [simple type, class
com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer]:
can not instantiate from JSON object (need to add/enable type information?)
I have the following in my proguard-project.txt file:
-keepattributes *Annotation*,EnclosingMethod
-keep public class org.w3c.** {public private protected *;}
-dontwarn org.w3c.**
-keep public class org.joda.time.** {public private protected *;}
-dontwarn org.joda.time.**
-keep public class org.restlet.** { *; }
-dontwarn org.restlet.**
-keep public class org.codehaus.** { *; }
-dontwarn org.codehaus.**
-keepattributes Signature
-keepnames class com.fasterxml.jackson.** { *; }
-dontwarn com.fasterxml.jackson.databind.**
And my class the error refers to looks like:
public class WasteCollectionAreasContainer {
public List<WasteCollectionAreas> wasteCollectionAreasList;
public List<WasteCollectionAreas> getWasteCollectionAreasList() {
return wasteCollectionAreasList;
}
public void setWasteCollectionAreasist(List<WasteCollectionAreas> wasteCollectionAreasList) {
this.wasteCollectionAreasList = wasteCollectionAreasList;
}
public WasteCollectionAreasContainer() {
wasteCollectionAreasList = new ArrayList<WasteCollectionAreas>();
}
#JsonCreator
public WasteCollectionAreasContainer(List<WasteCollectionAreas> wasteCollectionAreasList) {
this.wasteCollectionAreasList = wasteCollectionAreasList;
}
}
To reiterate prior to obfuscation through ProGuard the app works perfectly.
Can anyone help me solve this problem?
Add the following to your Proguard.config. It will help you locate the issue.
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
I have the following in my proguard-project.txt file
I believe you should be using proguard-android-optimize.txt, and not proguard-android.txt.
For completeness, thank Riley Hassell on Android Security Discussions for the tricks.
The error message
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type
[simple type, class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer]:
can not instantiate from JSON object (need to add/enable type information?)
suggests that the Jackson library is trying to deserialize your class using reflection, with its original name and its annotated constructor. ProGuard can't foresee this, so it may have removed or renamed the class and its constructor. You probably need to preserve them explicitly:
-keep class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer {
<init>(java.util.List);
}
There may be other similar classes/fields/methods that need to be preserved for the same reasons.
A better solution, in case anyone else has this problem, is the following:
# keep anything annotated with #JsonCreator
-keepclassmembers public class * {
#com.fasterxml.jackson.annotation.JsonCreator *;
}
That keeps any method annotated with JsonCreator, which is probably wanted to do in this case. If you have multiple classes needing to be loaded, then you can avoid having to specify each class individually.

How to tell ProGuard to keep everything in a particular package?

My application has many activities and uses native library too. With the default ProGuard configuration which Eclipse generates ProGuard removes many things - OnClick methods, static members, callback methods which my native library uses... Is it there a simple way to instruct ProGuard to NOT remove anything from my package? Removing things saves only about 2.5% of the application size, but breaks my application completely. Configuring, testing and maintaining it class by class in ProGuard configuration would be a pain.
EDIT This answer is 10 years old - it may not apply to newer proguard versions.
I think you need to add these flags at the very least (modify for you individual package names):
-keep class javax.** { *; }
-keep class org.** { *; }
-keep class twitter4j.** { *; }
Also, add these flags:
-dontshrink
-dontoptimize
-dontpreverify
Here's my whole config file: of my Proguard.cfg:
-dontshrink
-dontoptimize
-dontpreverify
-verbose
-dontwarn javax.management.**
-dontwarn java.lang.management.**
-dontwarn org.apache.log4j.**
-dontwarn org.apache.commons.logging.**
-dontwarn org.slf4j.**
-dontwarn org.json.**
-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 class javax.** { *; }
-keep class org.** { *; }
-keep class twitter4j.** { *; }
-keepclasseswithmembernames class * {
native <methods>;
}
-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 *;
}
As final result I found that just keeping all class members is not enough for the correct work of my application, nor necessary. I addded to the settings file this:
-keepclasseswithmembers class * {
void onClick*(...);
}
-keepclasseswithmembers class * {
*** *Callback(...);
}
The case with onClick* is for all methods which I address in android:onClick atribute in .xml layout files (I begin the names of all such methods with 'onClick').
The case with *Callback is for all callback methods which I call from my native code (through JNI). I place a suffix 'Callback' to the name of every such method.
Also I added few rows for some special cases with variables which I use from native code, like:
-keep class com.myapp.mypackage.SomeMyClass {
*** position;
}
(for a varible with name 'position' in a class with name 'SomeMyClass' from package com.myapp.mypackage)
All this is because these onClick, callback etc. must not only be present but also kept with their original names. The other things ProGuard can optimize freely.
The case with the native methods is important also, but for it there was a declaration in the generated from Eclipse file:
-keepclasseswithmembernames class * {
native <methods>;
}
I know this is an old question but I hope that the following information might help other people.
You can prevent ProGuard from removing anything in a certain package as follows;
-keep,allowoptimization,allowobfuscation class com.example.mypackage.** { *; }
Using the modifiers allowoptimization and allowobfuscation will make sure that ProGuard still obfuscates and optimizes the code. Shrinking will of course be disabled as intended.
You can easily verify how these -keep rules affect the code without the need to (re-)build using the ProGuard Playground.

ProGuard and Gson on Android (ClassCastException)

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)
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
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.
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
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.
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
So, I ended up ditching the Gson library and instead of converting my object to json using gson, I created a custom class in my app to serialize and deserialize the object and store the data that way.
I am overall more happy, even though this has cost me over 12 hours of trying to figure it out. Apparently, PROGUARD and gson must not like each other too much?
As A HUGELY added benefit to not having to use GSON, I noticed that by taking out the GSON library, my app size is cut in half. My app was 577kb and is now only 260kb after removing the gson lib.
It does look like your are keeping everything from your class (fields, methods and the class itself). But to make sure you can add -printseeds outputfile.txt to the proguard.cfg file to verify that proguard really keeps everything you need once obfuscation is done.
BTW, you might think about adding something like ACRA or Android Remote stacktrace that allows you to inspect stacktraces on a built app.
Just to add to all of the other answers, if you guys reached here, it means that you want to obfuscate your code AND use Gson.
If, at the end, you chose to -keep class your instances, it means that these Gson classes WILL NOT BE OBFUSCATED and this solution (or even Gson in general, is not an optimal solution for you).
In this case I would advise to Serialize the classes yourself and store them See #Jessy's answer.

Categories

Resources