升级Gradle、Kotlin及Java版本后Gson相关异常问题求助
升级Gradle、Kotlin和Java后Gson相关异常的解决方案
问题背景
将Gradle升级至8.2.1、Kotlin升级至1.9.21并切换到Java 17后,出现两类异常:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to cj.aException while processing periodic Task TaskWrapper{task=class y6.g, processed=false} java.lang.NoSuchMethodException: y6.g.<init> [class android.content.Context, class u6.a]
自定义BaseModel代码如下:
import com.google.gson.Gson abstract class BaseModel { inline fun <reified T: BaseModel> parseToJsonString(): String? { return try { parseToString<T>() } catch (e: Exception) { null } } inline fun <reified T: BaseModel> parseToString(): String { return Gson().toJson(this as T) } companion object { inline fun <reified T: BaseModel> fromJsonString(json: String): T? { return try { decodeFromString(json) } catch (e: Exception) { null } } inline fun <reified T: BaseModel> decodeFromString(json: String): T { return Gson().fromJson(json, T::class.java) } } }
已尝试添加以下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.** { *; } -keep class com.google.** { *; } -keep class sun.misc.** { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.google.gson.examples.android.model.** { *; } -keep class * implements com.google.gson.TypeAdapterFactory -keep class * implements com.google.gson.JsonSerializer -keep class * implements com.google.gson.JsonDeserializer -keep class * implements com.google.gson.* ##---------------End: proguard configuration for Gson ----------
原因分析
1. ClassCastException(LinkedTreeMap转自定义Model失败)
- 升级后ProGuard/R8的混淆规则生效更严格,自定义Model类被混淆后,Gson无法正确识别类结构,反序列化时只能用默认的LinkedTreeMap存储数据,导致类型转换失败。
- 现有ProGuard规则仅保留了Gson示例类和Gson相关接口实现,未保留项目中所有继承BaseModel的实体类,这是核心问题。
- Java 17的反射限制更严格,即使类未被完全混淆,反射获取类信息时也可能受限。
2. NoSuchMethodException(构造方法找不到)
- 混淆后的
y6.g类对应的原始类,其带Context和u6.a参数的构造方法被ProGuard/R8移除或重命名。 - 周期性任务通过反射调用该构造方法,但混淆规则未保留该构造方法的签名。
解决方案
针对ClassCastException的修复
- 修改ProGuard规则,保留所有BaseModel子类
在Gson混淆规则块中添加:
# 保留所有继承BaseModel的实体类及其字段、构造方法 -keep public class * extends your.package.name.BaseModel { <fields>; <init>(...); }
注意替换your.package.name为BaseModel实际所在的包路径。
- 优化BaseModel的Gson使用方式
避免每次序列化/反序列化都创建新的Gson实例,全局复用一个Gson对象,减少性能开销和潜在类加载问题:
import com.google.gson.Gson abstract class BaseModel { inline fun <reified T: BaseModel> parseToJsonString(): String? { return try { Companion.gson.toJson(this as T) } catch (e: Exception) { null } } companion object { private val gson = Gson() inline fun <reified T: BaseModel> fromJsonString(json: String): T? { return try { gson.fromJson(json, T::class.java) } catch (e: Exception) { null } } } }
针对NoSuchMethodException的修复
- 保留目标类的特定构造方法
通过混淆映射文件mapping.txt(位于build/outputs/mapping/release/目录)查找y6.g对应的原始类,然后在ProGuard规则中添加:
# 保留原始类的带Context和对应参数类的构造方法 -keep class your.package.name.OriginalTaskClass { <init>(android.content.Context, your.package.name.OriginalU6AClass); }
替换your.package.name.OriginalTaskClass和your.package.name.OriginalU6AClass为实际类路径。
- 无法定位原始类时的兜底方案
如果找不到具体类,可尝试保留所有周期性任务相关类:
# 假设周期性任务类都在特定包下 -keep class your.package.name.tasks.** { <init>(...); <methods>; }
适配Java 17的额外配置
在gradle.properties中添加:
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath=true android.enableR8.fullMode=false
关闭R8全模式可减少严格的代码移除,避免反射相关问题。
内容的提问来源于stack exchange,提问作者user21300258
相关产品推荐
相关产品推荐

