1. ホーム
  2. android

Gson EnumTypeAdapter で Proguard Obfuscation を使用すると AssertionError が発生する。

2023-09-27 22:30:19

質問

私のプロジェクトでは TypeAdapterGson をシリアライズ/デシリアライズする際に、オブジェクトのポリモーフィズムの状態を保持するために使用します。とにかく、このプロジェクトは開発テストの間はうまくいくのですが、リリースするときに proguard 難読化 を付けてリリースし、テストすると、クラッシュしてしまいます。

03-21 10:06:53.632: E/AndroidRuntime(12441): FATAL EXCEPTION: main
03-21 10:06:53.632: E/AndroidRuntime(12441): java.lang.AssertionError
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.TypeAdapters$EnumTypeAdapter.<init>(SourceFile:724)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.TypeAdapters$26.create(SourceFile:753)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.getAdapter(SourceFile:353)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(SourceFile:82)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(SourceFile:81)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(SourceFile:118)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(SourceFile:72)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.getAdapter(SourceFile:353)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJson(SourceFile:578)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJsonTree(SourceFile:479)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson.toJsonTree(SourceFile:458)
03-21 10:06:53.632: E/AndroidRuntime(12441):    at com.google.gson.Gson$3.serialize(SourceFile:137)

私のGson特有のproguardの設定は

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }

#This is extra - added by me to exclude gson obfuscation
-keep class com.google.gson.** { *; }

##---------------End: proguard configuration for Gson  ----------

この TypeAdapter 使っているのは

public final class GsonWorkshiftAdapter implements JsonSerializer<IWorkshift>, JsonDeserializer<IWorkshift> {
    private static final String CLASSNAME = "CLASSNAME";
    private static final String INSTANCE  = "INSTANCE";

    @Override
    public JsonElement serialize(IWorkshift src, Type typeOfSrc, JsonSerializationContext context) {
        String className = src.getClass().getCanonicalName();
        JsonElement elem = context.serialize(src);

        JsonObject retValue = new JsonObject();
        retValue.addProperty(CLASSNAME, className);
        retValue.add(INSTANCE, elem);

        return retValue;
    }

    @Override
    public IWorkshift deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject =  json.getAsJsonObject();
        JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
        String className = prim.getAsString();

        Class<?> klass = null;
        try { klass = Class.forName(className); }
        catch (ClassNotFoundException e) { throw new JsonParseException(e.getMessage()); }

        return context.deserialize(jsonObject.get(INSTANCE), klass);
    }
}

Gsonに特化したこのエラーについていろいろと検索してみましたが、参考になる回答は見つかりませんでした。しかし、私は見つけた 別の質問 を見つけました。

開発者コミュニティからのどんな助けでも感謝します。

どのように解決するのですか?

列挙のメンバーを保持するように要求する必要があるようです。 proguard の設定ファイルにこれを追加すると、私の場合はうまくいきました。

-keepclassmembers enum * { *; }

あるいは、もっと具体的に言うなら

-keepclassmembers enum com.your.package.** { *; }