2013-03-18 81 views
2

当试图在Proguard中使用EnumTypeAdapter时,它会在Gson.getAdapter()中产生一个AssertionError。这个错误似乎是由于输入个人信息丢失...以下是所有相关的源代码:使用proguard和GSON和RoboGuice在使用EnumTypeAdapter时失败

例外:

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)); 
} 
    } 

我已经搜遍遍寻找可能的解决方案,但没有找到太多的帮助。也许有人遇到过这种情况,可以指引我走向正确的方向吗?

回答

2

我仔细检查了所生成的APK反编译。我相信这个问题与某些枚举类型在混淆时失去其成员有关。

一定要保持枚举类成员:

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

而且 - 确保所有在GSON正在使用的类都被保留:

-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 *; 
} 

查看完整的配置@ pastebin.com/ r5Jg3yY2

+0

这不适合我,结果重构了我使用的一个枚举。 – scottyab 2013-12-16 10:54:06

+0

不适用于我... – starkej2 2015-02-20 20:42:11