当尝试将 EnumTypeAdapter 与 Proguard 一起使用时,会导致 Gson.getAdapter() 中出现 AssertionError。这个错误似乎是由于类型信息丢失......下面是所有相关的源代码:
例外:
03-18 13:27:12.905: ERROR/roboguice(12139): Throwable caught during background processing
java.lang.AssertionError
at com.google.gson.internal.bind.TypeAdapters$EnumTypeAdapter.<init>(Unknown Source)
at com.google.gson.internal.bind.TypeAdapters$24.create(Unknown Source)
at com.google.gson.Gson.getAdapter(Unknown Source)
正在使用的 EnumTypeAdapter:
public class OperationResultSerializer implements JsonDeserializer<OperationResult>, JsonSerializer<OperationResult> {
@Override
public OperationResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
int value = json.getAsJsonPrimitive().getAsInt();
return OperationResult.values()[value];
}
@Override
public JsonElement serialize(OperationResult src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.ordinal());
}
}
我如何构建我的 GSON 对象:
gson = new GsonBuilder()
.registerTypeAdapter(Calendar.class, new WcfCalendarSerializer())
.registerTypeAdapter(OperationResult.class, new OperationResultSerializer())
.registerTypeAdapter(FieldName.class, new FieldNameSerializer())
.registerTypeAdapter(MealType.class, new MealTypeSerializer())
.create();
我的 ProGuard 配置:
#-dontusemixedcaseclassnames: Necessary when building on windows where x.class and X.class is the same file
-dontusemixedcaseclassnames
-keepattributes *Annotation*
-keepattributes Signature
# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * extends android.app.Application
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keep class com.google.inject.** { *; }
-keep class javax.inject.** { *; }
-keep class javax.annotation.** { *; }
-keep class roboguice.** { *; }
-keep class * extends android.preference.Preference {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
###Action bar sherlock
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
###RoboGuice
-keepclassmembers class * {
@com.google.inject.Inject <init>(...);
}
-keepclassmembers class * {
void *(**On*Event);
}
-keep public class roboguice.**
-keep class com.google.inject.**
-keep class com.google.gson.** {*;}
#datacontract
-keep public class com.ordering.datacontract.*
-keepclassmembers class com.ordering.datacontract.*
# LVL License binder class
-keep class com.android.vending.licensing.ILicensingService
-dontwarn
-ignorewarnings
如前所述,我怀疑由于类型信息丢失而导致某些事情失败 - 在深入研究 GSON 源代码后,这是为解析 EnumTypeAdapter 而调用的代码......显然 getEnumConstants 返回的名称不存在classOfT 类型的字段。但我不确定这怎么可能。
private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
private final Map<String, T> nameToConstant = new HashMap<String, T>();
private final Map<T, String> constantToName = new HashMap<T, String>();
public EnumTypeAdapter(Class<T> classOfT) {
try {
for (T constant : classOfT.getEnumConstants()) {
String name = constant.name();
SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class);
if (annotation != null) {
name = annotation.value();
}
nameToConstant.put(name, constant);
constantToName.put(constant, name);
}
} catch (NoSuchFieldException e) {
throw new AssertionError();
}
}
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return nameToConstant.get(in.nextString());
}
public void write(JsonWriter out, T value) throws IOException {
out.value(value == null ? null : constantToName.get(value));
}
}
我已经到处寻找可能的解决方案,但没有找到太多帮助。也许有人以前遇到过这种情况并可以指出我正确的方向?