You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:37:09