当前位置: 首页 > 知识库问答 >
问题:

当使用EnumTypeAdapter时,将proguard与GSON和RoboGuice一起使用失败

谢高峯
2023-03-14

当试图将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));
}
  }

我到处寻找可能的解决办法,但没有找到太多的帮助。也许有人以前遇到过这种情况,可以给我指明正确的方向?

共有1个答案

张唯
2023-03-14

我通过并检查了反编译的结果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 *;
 }
 类似资料:
  • 在序列化/反序列化过程中,我的项目在中实现了一个,用于保留对象的多态性状态。不管怎样,该项目在开发测试中工作得很好,但当它用proguard混淆发布并测试时,它就崩溃了。 我的Gson特定的proguard配置是: 我正在使用的打字适配器是: 任何来自开发者社区的帮助都将不胜感激。

  • 问题内容: 我正在处理一些服务器代码,其中客户端以JSON形式发送请求。我的问题是,有许多可能的请求,每个请求的实现细节都不尽相同。因此,我想使用一个Request接口,它定义为: 从那里,我在名为如下的类中实现了接口: 为了使用JSON,我创建了一个实例并注册了一个,如下所示: 然后,如下面的代码片段所示,我使用了它: 我得到了预期的输出。 我希望做的是用类似于以下内容的内容替换该行,但是这样做

  • 我的适配器 我的持有者 类myHolder(itemView:View):recyclerview.viewholder(itemView){} 第二个 提前致谢

  • 我有一个带有Spring(5.7.2)Web/Security的REST API项目。 我只有一个表,它包含一个id和一个名称。 当我删除光盘时,我的DiscsService会 当我需要插入或更新时,我会: 我了解到,当您希望在同一事务中使用值(提交之前)时,将使用,并且将同步并清空SQL缓存。 在我的例子中,我看到我在数据库中插入/更新或删除了值。 我应该使用flush()(我认为不应该),但可

  • 问题内容: 我正在尝试创建一个通用类以与Google Gson一起使用。我已经创建了课程。此类具有以下方法: 目标是该方法应该能够与我设置了GsonJsonConverterImplementation的任何Type一起使用。不幸的是,它不起作用,也不能代替T 使用。我确信问题是由于我对Java泛型类型缺乏理解而引起的。在Gson上使用泛型的正确方法是什么? 使用Kris的答案进行 编辑,我认为这

  • 问题内容: 我在应用程序中使用Gson,为此,我使用了一些名称与使用Json相同的类。我的应用程序运行良好,但是在编写proguard时,应用程序崩溃了,我猜有些类正在缩小。我的错误是: java.lang.ClassCastException:com.google.gson.internal.StringMap无法转换为com.sample.package.GsonClass 问题答案: 您需要