2

Proguard で EnumTypeAdapter を使用しようとすると、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));
}
  }

私は可能な解決策をあちこち探しましたが、あまり助けが見つかりませんでした。誰かが以前にこれに遭遇したことがあり、私を正しい方向に向けることができますか?

4

1 に答える 1

2

結果として得られた APK を逆コンパイルして調べました。この問題は、難読化中に一部の列挙型がメンバーを失うことに関連していると思います。

enum クラス メンバーを保持するようにしてください。

-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 で完全な構成を参照してください。

于 2013-03-21T15:06:50.380 に答える