Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proguard - PersistenceException: Constructor not matched for class

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.

like image 617
Abbas Avatar asked Nov 21 '17 07:11

Abbas


1 Answers

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.* *;
}
like image 80
Ricardo Avatar answered Nov 14 '22 22:11

Ricardo