当用空列表和 minifyEnabled true 序列化模型时抛出 KotlinReflectionInternalError 导致 Jackson 序列化失败

Jackson serialisation fails by throwing KotlinReflectionInternalError when serializing model with empty list and minifyEnabled true

我的 build.gradle 文件中有 minifyEnabled true,假设我有一个模型

data class SomeModel(
    val numberList: List<Int>
)

numberList 变量具有某些值时,它会正确序列化

SomeModel(listOf(1, 2, 3))

但如果numberList的内容为空则序列化失败

SomeModel(listOf()) // or SomeModel(emptyList())

如果我将代码更改为 minifyEnabled false

,以上两种情况都可以正常工作

我这样连载

jsonMapper.writeValueAsString(someModel)

我的杰克逊 JsonMapper 看起来像这样

JsonMapper().apply {
    enable(MapperFeature.INFER_PROPERTY_MUTATORS)
    enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
    configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    registerModule(KotlinModule())
}

我什至在 proguard-rules.pro 文件中添加了 class

-keep  class org.package.SomeModel {
    <fields>;
}

# tried this also
-keep  class org.package.SomeModel {
    *;
}

错误日志如下

kotlin.reflect.jvm.internal.KotlinReflectionInternalError: No accessors or field is found for property val kotlin.collections.EmptyList.serialVersionUID: kotlin.Long
    at kotlin.reflect.jvm.internal.KPropertyImplKt.computeCallerForAccessor(KPropertyImpl.kt:240)
    at kotlin.reflect.jvm.internal.KPropertyImplKt.access$computeCallerForAccessor(KPropertyImpl.kt:1)
    at kotlin.reflect.jvm.internal.KPropertyImpl$Getter$caller.invoke(KPropertyImpl.kt:156)
    at kotlin.reflect.jvm.internal.KPropertyImpl$Getter$caller.invoke(KPropertyImpl.kt:147)
    at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
    at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
    at kotlin.reflect.jvm.internal.KPropertyImpl$Getter.getCaller(Unknown Source:7)
    at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:63)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector.getCorrespondingGetter(KotlinAnnotationIntrospector.kt:145)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector.hasRequiredMarker(KotlinAnnotationIntrospector.kt:110)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector.access$hasRequiredMarker(KotlinAnnotationIntrospector.kt:23)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector$hasRequiredMarker$hasRequired.invoke(KotlinAnnotationIntrospector.kt:40)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector$hasRequiredMarker$hasRequired.invoke(KotlinAnnotationIntrospector.kt:23)
    at com.fasterxml.jackson.module.kotlin.ReflectionCache.javaMemberIsRequired(ReflectionCache.kt:56)
    at com.fasterxml.jackson.module.kotlin.KotlinAnnotationIntrospector.hasRequiredMarker(KotlinAnnotationIntrospector.kt:33)
    at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.hasRequiredMarker(AnnotationIntrospectorPair.java:318)
    at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.hasRequiredMarker(AnnotationIntrospectorPair.java:318)
    at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getMetadata(POJOPropertyBuilder.java:229)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._anyIndexed(POJOPropertiesCollector.java:1197)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._sortProperties(POJOPropertiesCollector.java:1099)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:425)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueAccessor(POJOPropertiesCollector.java:227)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueAccessor(BasicBeanDescription.java:258)
    at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:391)
    at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.buildCollectionSerializer(BasicSerializerFactory.java:705)
    at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.buildContainerSerializer(BasicSerializerFactory.java:647)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:200)
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:169)
    at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1473)
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1441)
    at com.fasterxml.jackson.databind.SerializerProvider.findPrimaryPropertySerializer(SerializerProvider.java:651)
    at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddPrimarySerializer(PropertySerializerMap.java:72)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._findAndAddDynamic(BeanPropertyWriter.java:895)
E/AndroidRuntime:     at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:706)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4485)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3740)
    at org.nvest.BiTool.test1(BiTool.kt:173)
    at org.bharti.axa.ui.HomeScreenActivity$onCreate.onClick(HomeScreenActivity.kt:92)
    at android.view.View.performClick(View.java:7509)
    at android.view.View.performClickInternal(View.java:7486)
    at android.view.View.access00(View.java:841)
    at android.view.View$PerformClick.run(View.java:28709)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8060)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)

错误提示No accessors or field is found for property val kotlin.collections.EmptyList.serialVersionUID: kotlin.Long

所以 kotlin.reflect 知道 EmptyList.serialVersionUID 但它找不到 Jackson 序列化空列表。它知道 EmptyList.serialVersionUID 而实际上无法访问可能意味着它在 kotlin.collections.EmptyListkotlin.Metadata 中,但不在 class 本身中。

因为这只发生在 minifyEnabled = true 上,看来 r8 剥离了 kotlin.collections.EmptyList.serialVersionUID 但实际上并没有更新 kotlin.collections.EmptyListkotlin.Metadata 以避免错误地指示该字段仍然存在。

这可能是 r8 的错误,并且 r8 与 android gradle 插件打包在一起,因此更新 android gradle 最新稳定版本的插件应该可以解决这个问题。如果没有,我建议在 Google 问题跟踪器中提交一个 r8 错误。