Mein Projekt implementiert ein TypeAdapter
In Gson
während der Serialisierung / Deserialisierung, um den Polymorphismuszustand des Objekts zu erhalten. Wie auch immer, das Projekt funktioniert gut während der Entwicklungstests, aber wenn es mit Proguard-Verschleierung veröffentlicht und getestet wird, stürzt es einfach ab.
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)
Meine Gson-spezifische Proguard-Konfiguration lautet:
##---------------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 ----------
Der von mir verwendete TypeAdapter lautet:
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);
}
}
Ich habe viel nach diesem für Gson spezifischen Fehler gesucht, aber keine hilfreiche Antwort gefunden. Ich fand jedoch eine andere Frage mit dem ähnlichen Problem.
Jede Hilfe von der Entwickler-Community wäre dankbar.
Antworten:
Es scheint, als müssten wir darum bitten, dass die Mitglieder der Aufzählungen erhalten bleiben. Das Hinzufügen zur Proguard-Konfigurationsdatei hat bei mir funktioniert:
-keepclassmembers enum * { *; }
Oder, wenn Sie genauer sein möchten,
-keepclassmembers enum com.your.package.** { *; }
quelle
Enum.values()
) und diese verwendetname()
, um das Feld zu finden und nach zu suchen@SerializedName
. Proguard benannte die Felder jedoch um, sodass Gson sie nicht findet.-keepclassmembers enum
verhindert, dass Proguard die Felder umbenennt. (Beachten Sie, dass es eine Pull-Anfrage für Gson gibt , um das Problem zu umgehen.)GSON löst diesen AssertionError aus, wenn Enumerationskonstanten aus JSON-Daten nicht deserialisiert werden können, und führt eine Introspektion der Felder der Enum-Klasse durch. Leider werden die Details der zugrunde liegenden NoSuchFieldException verschluckt.
Sie sollten sicherstellen, dass Sie die Namen der Aufzählungsfelder (und der Felder im Allgemeinen) beibehalten, die serialisiert werden. Standardmäßig kann ProGuard sie umbenennen oder sogar entfernen. Zum Beispiel mit einigen Platzhaltern:
-keepclassmembers class com.example.domain.** { <fields>; }
quelle
<fields>
hier ein Platzhalter für den Namen der Aufzählungsfelder oder sollte es geschrieben werden , wie sie ist?Es wird bereits empfohlen, Proguard so zu konfigurieren, dass alle mit serialisierten Objekten verbundenen Aufzählungen erhalten bleiben. Die Tatsache, dass ich alle meine Aufzählungen explizit auflisten muss, gefällt mir nicht wirklich. Diese Lösung ist schwer zu pflegen. Eine etwas bessere Lösung, die ich mir ausgedacht habe, ist die folgende.
Verwenden Sie eine leere Schnittstelle, um anzugeben, dass eine Klasse oder Aufzählung an der Gson-Serialisierung teilnimmt:
public interface GsonSerializable { } public class MyClass implements GsonSerializable { public enum MyEnum implements GsonSerializable { enumvalue1, enumvalue2 } public MyEnum mydata1; }
Verwenden Sie eine Proguard-Konfiguration, die sowohl die Schnittstelle als auch alle Klassen / Aufzählungen enthält, die sie implementieren:
# 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
Das war's, solange Ihre Klassen und Aufzählungen die Schnittstelle verwenden, sollten Sie in Ordnung sein. Sie können das Vorhandensein dieser Schnittstelle auch in Ihren Serialisierungs- / Deserialisierungsmethoden erzwingen, damit Sie es nicht vergessen, wenn Sie später eine neue Klasse hinzufügen:
public String serializeWithGson(GsonSerializable object) { ... }
Auch in Ihrer Konfiguration die Zeile mit 'com.google.gson.examples.android.model. ** {*; } 'bezieht sich auf einen Google-bezogenen Beispielcode, daher halte ich dies nicht für erforderlich.
quelle
In meinem Fall wurde Proguard für
-keep
einzelne Klassen konfiguriert, die von Gson berührt wurden. Der Fehler wurde jedoch behoben, als ich Proguard so konfigurierte, dass das Paket beibehalten wurde , in dem sich diese einzelnen Klassen befanden :-keep class com.company.library.model.** { *; }
quelle
Nachdem ich auf dasselbe Problem gestoßen war, ging ich durch und untersuchte die resultierende dekompilierte APK. Ich glaube, das Problem hängt damit zusammen, dass ein Aufzählungstyp seine Mitglieder während der Verschleierung verliert.
Achten Sie darauf, Aufzählungen zu behalten:
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
Stellen Sie außerdem sicher, dass ALLE in GSON verwendeten Klassen beibehalten werden:
-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 *; }
Siehe vollständige Konfiguration unter pastebin.com/r5Jg3yY2
quelle
Bitte überprüfen Sie folgende Dinge:
Wird die Datei proguard-rules.pro im App-Verzeichnis hinzugefügt.
Ist der in build.gradle (Modul: App) definierte Pfad definiert? Die Pfaddefinition ist wie folgt korrekt:
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
Wenn die obigen 2 Schritte in Ordnung sind, fügen Sie bitte die folgende Zeile (Regel) in die Progaurd-Datei ein.
-keepclassmembers enum * {*; }}
Reinigen Sie das Projekt, erstellen Sie es und führen Sie es erneut aus.
quelle