在使用EnumTypeAdapter时,对GSON和RoboGuice使用proguard会失败 [英] Using proguard with GSON and RoboGuice fails when using a EnumTypeAdapter
问题描述
当试图在Proguard中使用EnumTypeAdapter时,它会在Gson.getAdapter()中产生一个AssertionError。这个错误似乎是由于类型信息丢失...下面是所有相关的源代码:
例外:
03-18 13:27:12.905:错误/ roboguice(12139):在后台处理过程中捕获到
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实现了JsonDeserializer< OperationResult> ;, JsonSerializer< OperationResult> {
@Override
public OperationResult deserialize(JsonElement json,Type typeOfT,JsonDeserializationContext context)throws JsonParseException {
int value = json.getAsJsonPrimitive()。getAsInt();
返回OperationResult.values()[value];
$ b @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:在x.class和X.class是相同文件的窗口上构建时必需的
$ b $ p如前所述,由于类型信息丢失,我怀疑有些东西是失败的 - 在深入研究GSON源代码之后,这是调用的代码解析EnumTypeAdapter ...显然,getEnumConstants返回一个不存在的名称作为类型classOfT的字段。但我不确定这是可能的。
-dontusemixedcaseclassnames
-keepattributes *注释*
-keepattributes签名
#保留所有枚举类所需的特殊静态方法。
-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特定类
-keep class sun.misc.Unsafe {*; }
#-keep class com.google.gson.stream。** {*; }
###操作栏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许可证绑定程序类
-keep class com.android.vending.licensing.ILicensingService
-dontwarn
--ignorewarnings
private static final class EnumTypeAdapter< T extends Enum< T>>扩展TypeAdapter< T> {
private final Map< String,T> nameToConstant = new HashMap< String,T>();
private final Map< T,String> constantToName = new HashMap< T,String>(); (T常量:classOfT.getEnumConstants()){
字符串名称=常量名称($)
public EnumTypeAdapter(Class< T> classOfT){
try {
();
SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class);
if(annotation!= null){
name = annotation.value();
}
nameToConstant.put(name,constant);
constantToName.put(常量,名称);
}
} catch(NoSuchFieldException e){
throw new AssertionError();
$ b $ public T read(JsonReader in)throws IOException {
if(in.peek()== JsonToken.NULL){
in.nextNull );
返回null;
}
return nameToConstant.get(in.nextString());
$ b $ public void write(JsonWriter out,T value)throws IOException {
out.value(value == null?null:constantToName.get(value));
}
}
我已经搜索了所有可能的解决方案,但没有找到了很多帮助。也许有人遇到过这种情况,可以指引我走向正确的方向吗?
解决方案我检查了反编译的结果APK。我相信这个问题与某些枚举类型在模糊处理期间失去其成员有关。
请确保保留enum类成员:
-keepclassmembers枚举* {
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
When trying to use a EnumTypeAdapter with Proguard, it results in a AssertionError in Gson.getAdapter(). This error seems to be due to type information being lost... below is all the relevant source code:
The Exception:
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)
The EnumTypeAdapter being used:
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()); } }
How I am constructing my GSON object:
gson = new GsonBuilder() .registerTypeAdapter(Calendar.class, new WcfCalendarSerializer()) .registerTypeAdapter(OperationResult.class, new OperationResultSerializer()) .registerTypeAdapter(FieldName.class, new FieldNameSerializer()) .registerTypeAdapter(MealType.class, new MealTypeSerializer()) .create();
My ProGuard Config:
#-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
As stated earlier, I suspect something is failing due to type information being lost - after digging into the GSON source code, this is the code that is called to resolve the EnumTypeAdapter... clearly the getEnumConstants is returning a Name that does not exist as a field of the type classOfT. But I am unsure how that is possible.
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)); } }
I have searched all over for possible solutions but have not found much help. Maybe someone has run into this before and can point me in the right direction?
解决方案I went through and examined the resulting APK decompiled. I believe the problem is related to some enum type losing its members during obfuscation.
Be sure to keep enum class members:
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
Also - make sure ALL of the classes being used in GSON are being retained:
-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 *; }
See full config @ pastebin.com/r5Jg3yY2
这篇关于在使用EnumTypeAdapter时,对GSON和RoboGuice使用proguard会失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!