使用Proguard模糊处理时Gson EnumTypeAdapter中出现Assert错误

jhiyze9q  于 2022-11-06  发布在  其他
关注(0)|答案(7)|浏览(125)

我的项目在序列化/反序列化期间在Gson中实现了一个TypeAdapter,以保留对象的多态状态。无论如何,项目在开发测试期间工作正常,但是当它发布proguard obfuscation并进行测试时,它就崩溃了。

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,但没有找到任何有用的答案。然而,我发现another question与类似的问题。
我们将非常感谢来自开发人员社区的任何帮助。

qq24tv8q

qq24tv8q1#

看起来我们必须请求保留枚举的成员。将其添加到proguard配置文件对我很有效:

-keepclassmembers enum * { *; }

或者,如果你想更具体一点,

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

vu8f3i0k2#

当GSON无法从JSON数据中反序列化枚举常量时,它会抛出这个AssertionError,对枚举类的字段执行内省。不幸的是,它吞下了底层NoSuchFieldException的细节。
您应该确保保留序列化的枚举字段(以及一般字段)的名称。默认情况下,ProGuard可能会重命名甚至删除它们。例如,使用一些通配符:

-keepclassmembers class com.example.domain.**{
    <fields>;
}
8ulbf1ek

8ulbf1ek3#

已经有人建议您需要以一种方式来配置Profuard,使其保持与序列化对象相关的每个枚举的完整性。我真的不喜欢我必须显式列出所有枚举的事实,这种解决方案很难维护。我想出了一个稍微好一点的解决方案,如下所示。
使用空接口指示类或枚举参与Gson序列化:

public interface GsonSerializable { }

public class MyClass implements GsonSerializable {

    public enum MyEnum implements GsonSerializable {
        enumvalue1, enumvalue2
    }

    public MyEnum mydata1;
}

使用保留接口和实现它的所有类/枚举的Proguard配置:


# keep GsonSerializable interface, it would be thrown away by proguard since it is empty

-keep class com.example.GsonSerializable

# member fields of serialized classes, including enums that implement this interface

-keepclassmembers class * implements com.example.GsonSerializable {
    <fields>;
}

# also keep names of these classes. not required, but just in case.

-keepnames class * implements com.example.GsonSerializable

就是这样,只要你的类和枚举使用这个接口,你就可以了。你也可以在你的序列化/反序列化方法中强制这个接口的存在,这样当你以后添加一个新类的时候就不会忘记它了:

public String serializeWithGson(GsonSerializable object) { ... }

此外,在您的配置中,带有“com.google.gson.examples.android.model.**{ *;}'指的是一些Google相关的示例代码,所以我认为没有必要。

tzdcorbm

tzdcorbm4#

在我的例子中,proguard被配置为-keep Gson所涉及的单个类,但是当我将proguard配置为保留这些单个类所在的 package 时,错误消失了:

-keep class com.company.library.model.**{ *; }
pcww981p

pcww981p5#

在遇到同样的问题后,我检查了反编译后的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 *;
 }

请访问www.example.com查看完整配置pastebin.com/r5Jg3yY2

n9vozmp4

n9vozmp46#

请确认以下事项-
1.添加proguard-rules.pro文件添加到应用程序目录中。
1.是否为build.gradle(module:app)文件路径定义中定义的路径正确,如下所示-
如果您有一个新的密码,请使用这个密码。
1.如果以上两个步骤是好的,那么请添加以下行(规则)在progaurd文件-

  • 保留类成员枚举 * { *;}
    1.清理、生成项目并再次运行。
ghhkc1vu

ghhkc1vu7#

应用androidx.注解。在枚举类上保留注解。例如:

@Keep
enum class PlayerType {
    PRO,
    INTERMEDIATE,
    BASIC
}

相关问题