2013-03-18 126 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

相關問題