如何解决Proguard混淆导致的Jackson反序列化异常?
Proguard混淆导致Jackson解析Kotlin Data Class异常的解决方案
问题重现
开启Proguard混淆后,程序运行时出现Jackson解析异常:
Exception in thread "DefaultDispatcher-worker-2" com.fasterxml.jackson.c.a.S: Instantiation of [simple type, class com.myapp.data.datasource.network.model.Linea] value failed for JSON property p0 due to missing (therefore NULL) value for creator parameter p0 which is a non-nullable type at [Source: (okio.RealBufferedSource$inputStream$1); line: 10, column: 1] (through reference chain: java.util.ArrayList[0]->com.myapp.data.datasource.network.model.Linea["p0"]) at com.fasterxml.jackson.c.a.O.createFromObjectWith(Unknown Source) at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(Unknown Source) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(Unknown Source) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(Unknown Source) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(Unknown Source) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(Unknown Source) at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(Unknown Source) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(Unknown Source) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(Unknown Source) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(Unknown Source) at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(Unknown Source) at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(Unknown Source) at com.fasterxml.jackson.databind.ObjectReader.readValue(Unknown Source) at retrofit2.converter.jackson.JacksonResponseBodyConverter.convert(Unknown Source) at retrofit2.converter.jackson.JacksonResponseBodyConverter.convert(Unknown Source) at retrofit2.OkHttpCall.parseResponse(Unknown Source) at retrofit2.OkHttpCall$1.onResponse(Unknown Source) at okhttp3.internal.connection.RealCall$AsyncCall.run(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@32d010be, Dispatchers.IO]
对应的Linea数据类代码:
data class Linea( val idLinea: String, val nameLinea: String )
尝试过以下Proguard规则但无效:
-keep class com.myapp.data.datasource.network.model.** { *; }
-keep class com.** { *; }
问题原因
Kotlin Data Class的构造函数参数会被Proguard混淆为p0、p1这类无意义名称,而Jackson(尤其是XML解析器)依赖参数名或Kotlin元数据来匹配JSON/XML字段与类属性。之前的规则仅保留了类和成员,但未保护构造函数参数名、Kotlin元数据(@Metadata注解),导致Jackson无法正确识别构造函数的参数对应关系,进而抛出"缺少p0参数"的异常。
正确的Proguard配置方案
方案1:针对目标数据类的精准规则
直接保留Linea类的构造函数、参数名及必要元数据:
# 保留Linea类的构造函数(参数类型需与原类一致) -keepclassmembers class com.myapp.data.datasource.network.model.Linea { public <init>(java.lang.String, java.lang.String); } # 保留类名不被混淆 -keepnames class com.myapp.data.datasource.network.model.Linea # 保留参数名,供Jackson识别构造参数 -keepattributes ParameterNames # 保留Kotlin元数据,确保Jackson Kotlin模块能正确解析数据类 -keep class kotlin.Metadata { *; }
方案2:针对整个网络模型包的通用规则
如果有多个类似的数据类,可以批量配置:
# 保留网络模型包下所有类的构造函数 -keep class com.myapp.data.datasource.network.model.** { <init>(...); } # 保留包下所有类名不被混淆 -keepnames class com.myapp.data.datasource.network.model.** # 保留类成员的getter/setter和字段 -keepclassmembers class com.myapp.data.datasource.network.model.** { *** get*(); void set*(***); kotlin.jvm.JvmField *; } # 保留Jackson和Kotlin解析所需的属性 -keepattributes Signature, InnerClasses, EnclosingMethod, AnnotationDefault, ParameterNames -keep class kotlin.Metadata { *; }
规则说明
<init>(...):保留类的所有构造函数,避免构造函数被混淆或移除-keepnames:仅保留类名/成员名不被混淆,不强制保留成员本身ParameterNames属性:保留构造函数和方法的参数名,Jackson依赖此匹配字段kotlin.Metadata:Kotlin类的元数据注解,Jackson Kotlin模块需要它来识别Data Class的结构get*()/set*():保留属性的访问器,确保Jackson能通过反射读写属性
内容的提问来源于stack exchange,提问作者NullPointerException
相关产品推荐
相关产品推荐

