AssertionError in Gson EnumTypeAdapter bij gebruik van Proguard Obfuscation

Mijn project implementeert een TypeAdapterin Gsontijdens serialisatie/deserialisatie om de polymorfismestatus van het object te behouden. Hoe dan ook, het project werkt prima tijdens ontwikkelingstests, maar wanneer het wordt vrijgegeven met proguard obfuscationen wordt getest, crasht het gewoon.

03-21 10:06:53.632: E/AndroidRuntime(12441): FATAL EXCEPTION: main
03-21 10:06:53.632: E/AndroidRuntime(12441): java.lang.AssertionError
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.TypeAdapters$EnumTypeAdapter.<init>(SourceFile:724)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.TypeAdapters$26.create(SourceFile:753)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.getAdapter(SourceFile:353)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(SourceFile:82)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(SourceFile:81)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(SourceFile:118)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(SourceFile:72)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.getAdapter(SourceFile:353)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJson(SourceFile:578)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJsonTree(SourceFile:479)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJsonTree(SourceFile:458)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson$3.serialize(SourceFile:137)

Mijn Gson-specifieke proguard-configuratie is:

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
#This is extra - added by me to exclude gson obfuscation
-keep class com.google.gson.** { *; }
##---------------End: proguard configuration for Gson  ----------

De TypeAdapterdie ik gebruik is:

public final class GsonWorkshiftAdapter implements JsonSerializer<IWorkshift>, JsonDeserializer<IWorkshift> {
    private static final String CLASSNAME = "CLASSNAME";
    private static final String INSTANCE  = "INSTANCE";
    @Override
    public JsonElement serialize(IWorkshift src, Type typeOfSrc, JsonSerializationContext context) {
        String className = src.getClass().getCanonicalName();
        JsonElement elem = context.serialize(src);
        JsonObject retValue = new JsonObject();
        retValue.addProperty(CLASSNAME, className);
        retValue.add(INSTANCE, elem);
        return retValue;
    }
    @Override
    public IWorkshift deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject =  json.getAsJsonObject();
        JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
        String className = prim.getAsString();
        Class<?> klass = null;
        try { klass = Class.forName(className); }
        catch (ClassNotFoundException e) { throw new JsonParseException(e.getMessage()); }
        return context.deserialize(jsonObject.get(INSTANCE), klass);
    }
}

Ik heb veel gezocht naar deze fout specifiek voor Gson, maar kon geen nuttig antwoord vinden. Ik vond echter een andere vraagmet hetzelfde probleem.

Alle hulp van de ontwikkelaarsgemeenschap wordt op prijs gesteld.


Antwoord 1, autoriteit 100%

Het lijkt erop dat we moeten verzoeken dat de leden van de opsommingen worden bewaard.
Dit toevoegen aan het proguard-configuratiebestand werkte voor mij:

-keepclassmembers enum * { *; }

Of, als u specifieker wilt zijn,

-keepclassmembers enum com.your.package.** { *; }

Antwoord 2, autoriteit 10%

GSON genereert deze AssertionError wanneer het er niet in slaagt om opsommingsconstanten uit JSON-gegevens te deserialiseren, waarbij introspectie wordt uitgevoerd op de velden van de enum-klasse. Helaas slikt het de details van de onderliggende NoSuchFieldException in.

Je moet ervoor zorgen dat je de namen behoudt van de enum-velden (en van velden in het algemeen) die geserialiseerd zijn. Standaard kan ProGuard ze hernoemen of zelfs verwijderen. Bijvoorbeeld, met enkele wildcards:

-keepclassmembers class com.example.domain.** {
    <fields>;
}

Antwoord 3, autoriteit 7%

Er is al gesuggereerd dat u Proguard zo moet configureren dat elke opsomming met betrekking tot geserialiseerde objecten intact blijft. Ik vind het niet echt prettig dat ik al mijn opsommingen expliciet moet opsommen, deze oplossing is moeilijk te onderhouden. Een iets betere oplossing die ik bedacht is de volgende.

Gebruik een lege interface om aan te geven dat een klasse of opsomming deelneemt aan Gson-serialisatie:

public interface GsonSerializable { }
public class MyClass implements GsonSerializable {
    public enum MyEnum implements GsonSerializable {
        enumvalue1, enumvalue2
    }
    public MyEnum mydata1;
}

Gebruik een Proguard-configuratie die zowel de interface als alle klassen/enums die deze implementeren behoudt:

# keep GsonSerializable interface, it would be thrown away by proguard since it is empty
-keep class com.example.GsonSerializable
# member fields of serialized classes, including enums that implement this interface
-keepclassmembers class * implements com.example.GsonSerializable {
    <fields>;
}
# also keep names of these classes. not required, but just in case.
-keepnames class * implements com.example.GsonSerializable

Dat is het, zolang je klassen en opsommingen de interface gebruiken, zou het goed moeten komen. U kunt de aanwezigheid van deze interface ook afdwingen in uw serialisatie-/deserialisatiemethoden, zodat u deze niet vergeet wanneer u later een nieuwe klasse toevoegt:

public String serializeWithGson(GsonSerializable object) { ... }

Ook in uw configuratie de regel met ‘com.google.gson.examples.android.model.** { *; }’ verwijst naar een aan Google gerelateerde voorbeeldcode, dus ik denk niet dat dit nodig is.


Antwoord 4, autoriteit 4%

In mijn geval was proguard geconfigureerd om -keepindividuele klassen die door Gson worden aangeraakt, maar de fout ging weg toen ik proguard configureerde om het pakkette behouden waarin die individuele klassen woonde:

-keep class com.company.library.model.** { *; }

Antwoord 5, autoriteit 3%

Na hetzelfde probleem te hebben ondervonden, ging ik door en onderzocht de resulterende APK die was gedecompileerd. Ik denk dat het probleem te maken heeft met een enumtype dat zijn leden verliest tijdens verduistering.

Zorg ervoor dat u opsommingen bewaart:

-keepclassmembers enum * {
     public static **[] values();
     public static ** valueOf(java.lang.String);
 }

Zorg er ook voor dat alle lessen die in GSON worden gebruikt, vastgehouden:

-keep public class com.company.ordering.datacontract.** {
     public protected *;
 }
 -keep public class com.company.ordering.service.request.** {
     public protected *;
 }
 -keep public class com.company.ordering.service.response.** {
     public protected *;
 }

Zie volledige config @ Pastebin.com/r5JG3YY2


6

Controleer de volgende dingen –

  1. is Proguard-RULES.PRO-bestand toegevoegd toegevoegd in App Directory.

  2. is pad gedefinieerd in build.gradle (module: app) File Path Definitie is correct, zoals volgt –

    ProGuardfiles GetDefaultproguardfile (‘proguard-android-optimalisatie.txt’), ‘proguard-rules.pro’

  3. Als hierboven 2 stappen in orde is, voegt u de volgende regel (regel) in Progaurd-bestand toe –

    -KeepclassMembers Enum * {*; }

  4. Schoon, bouw het project en voer opnieuw uit.

Other episodes