Gson:java.lang.AssertionError: illegal type variable reference

加固Android应用后,特定系统版本(如7.x.x)出现崩溃,错误为java.lang.AssertionError:illegaltypevariablereference。问题源于Gson的fromJson方法在类型擦除后无法正确转换。解决方案包括检查混淆配置,如添加-keepattributesEnclosingMethod等,或修改代码,如指定泛型类型或使用JsonParser解析。通过指定TypeToken或传入.class,可确保类型转换成功,避免加固后的问题。谷歌官方也有类似问题报告。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、问题现象:

APP使用 XX加固助手 加固之后,在安卓 7.x.x 系统中会崩溃:错误信息为 java.lang.AssertionError: illegal type variable reference。

未加固之前并没有出现这个问题。

2、解决方案

(1)方案一:

网络搜索发现,大部分都说是开启混淆之后没配置好导致的,所以,根据网络搜索结果先检查 module 的 build.gradle 和 proguard-rules.pro 中的配置。

如果 buid.gradle 中开启了 minifyEnabled ,那么 proguard-rules.pro 中需要添加如下内容

-keepattributes EnclosingMethod

如果添加了上述内容之后依旧不生效,可添加下面的内容:

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod


如果该方案没能解决问题或没开启混淆,请参考方案二。

(2)、方案二

如果方案一中该配置的都处理了,但是在使用第三方加固时报错了,那说明第三方加固中配置了混淆参数,所以,此时我们只能修改我们代码中的内容。

1)、定位问题点

通过LOG或者BUGGLY查看具体的错误位置。如下图:



在上图中,我们可以定位到问题所在,是我们内部AFragment中的第159行和另一个BFragment中的132行。最终问题是指向 AFragment中的159行,那么,这里干了啥呢?

//GsonUtil.stringToList(str)是我们自己封装的一个工具类
List<String> settingList = GsonUtil.stringToList(userSetting);

stringToList(str)的具体逻辑为:

public static <T> ArrayList<T> stringToList(String gsonString) {
        ArrayList<T> list = null;
        //gson即Gson对象
        if (gson != null) {
            list = gson.fromJson(gsonString, new TypeToken<ArrayList<T>>() {
            }.getType());
        }
        return list;
    }

2)、复现规律和问题原因分析

然后重复测试发现如下规律:

  • 在没有使用 xxx加固助手之前,正常打包的APP在这地方并不会报错,可以正常运行;
  • 除 7.x.x 之外的系统,加固之后也不会报错;

根据上述规律猜测大致的问题原因如下:

  • 加固助手中对代码进行了二次混淆
  • 二次混淆之后,7.x.x系统中在调用 fromJson的转换时,虽然调用了获取类型的 TypeToken>().getType(),但这个getType()并没有生效——fromJson转换时会进行类型擦除,getType()不生效就表示没能获取到类型。然后,就挂掉了。。。
  • 为啥只有7.x.x 的系统中 getType()不生效呢?这个真的没想出来为啥。。。。

3)、问题的解决

在 B 中我们分析了问题原因应该是没有获取到数据类型,那么我们就需要想法子让 getType()拿到具体的数据类型。

A:首先我们做了如下尝试:

List<String> settingList = new ArrayList<>();
list = new Gson().fromJson(userSetting, new TypeToken<ArrayList<String>>() {
         }.getType());


上述代码中,在构造 TypeToken 对象时,我们指定了 ArrayList 接收参数的类型为 String,而不再是T。重新加固并安装运行 —— 不再报错!!

B: 然后又做了如下尝试:

/**
 * 转成list
 */
public static <T> ArrayList<T> stringToList(String gsonString, Class<T> cls) {
   ArrayList<T> list = new ArrayList<>();
   if (gson != null) {
      JsonArray array = new JsonParser().parse(gsonString).getAsJsonArray();
      for (final JsonElement elem : array) {
          list.add(gson.fromJson(elem, cls));
      }
   }
   return list;
}


在上述代码中,我们不再直接转换为List,而是使用GSON解析每一个对象,并且传入 .class —— 有了 .class 也就可以确定类型。重新加固并安装运行——不再报错!

3、最后:

加固后,不仅7.x系统会遇到该问题,8.x系统也会出现该问题,原因暂时还没有查明。

谷歌官方也有类似的issue,链接如下:

https://github.com/google/gson/issues/1343

有大佬给出了一个比较简单的解决方案如下:

public static <T> List<T> fromJsonToList(final String json, final Class<T> elementClass) {
	return gson.fromJson(json, TypeToken.getParameterized(List.class, elementClass).getType());
}

这个也用到了我们的项目中,确实能解决问题。

Process: com.example.kucun2, PID: 19286 java.lang.RuntimeException: Failed to invoke public com.example.kucun2.entity.data.SynchronizableEntity() with no args at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:113) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212) at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:63) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) at com.google.gson.Gson.fromJson(Gson.java:927) at com.google.gson.Gson.fromJson(Gson.java:892) at com.google.gson.Gson.fromJson(Gson.java:841) at com.example.kucun2.entity.data.ApiClient$1.onResponse(ApiClient.java:59) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) at java.lang.Thread.run(Thread.java:1042) Caused by: java.lang.InstantiationException: Can't instantiate abstract class com.example.kucun2.entity.data.SynchronizableEntity at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:343) at com.google.gson.internal.ConstructorConstructor$3.construct(Constru
最新发布
06-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值