【问题标题】:Jackson android NPE when use MixIn使用 MixIn 时的 Jackson android NPE
【发布时间】:2019-03-19 10:02:17
【问题描述】:

我的服务器 api 使用不同类型的多态对象。比如我有一个json:

{
  "eventType": "FirstType",
  "eventData": "some-useful-object"
}

和它的 kotlin 类:

sealed class NotificationEvent {

  data class SomeUsefulEvent(val eventData: String): NotificationEvent()

}

和混合类:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "eventType"
)
@JsonSubTypes(
    JsonSubTypes.Type(
        value = NotificationEvent.SomeUsefulEvent::class,
        name = "FirstType"
    )
)
abstract class NotificationEventMixIn

当我从客户端调用时

jsonMapper.readValue<NotificationEvent>(event.data)

应用程序因 NPE 崩溃:

java.lang.NullPointerException:尝试调用接口方法 'java.lang.Object java.util.Map.get(java.lang.Object)' 为空 对象引用 在 com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector._addFieldMixIns(AnnotatedFieldCollector.java:110) 在 com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector._findFields(AnnotatedFieldCollector.java:87) 在 com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector.collect(AnnotatedFieldCollector.java:41) 在 com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector.collectFields(AnnotatedFieldCollector.java:36) 在 com.fasterxml.jackson.databind.introspect.AnnotatedClass._fields(AnnotatedClass.java:349) 在 com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:321) 在 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:379) 在 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:308) 在 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:287) 在 com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:170) 在 com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164) 在 com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239) 在 com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:346) 在 com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:330) 在 com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:255) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:214) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137) 在 com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:411) 在 com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349) 在 com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264) 在 com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244) 在 com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142) 在 com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:477) 在 com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4178) 在 com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3997) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3011)

如何避免这种崩溃?

【问题讨论】:

  • 干得好,但如果您已经找到了此问题的答案,请从问题中删除答案并将其作为答案放在下面。找到它会容易得多。
  • @MichałZiober 已更新。实际上,这不是答案 - 这是一种解决方法。它看起来很奇怪和hacky。此外,它在不同设备上的工作方式不同,这有点奇怪。这就是为什么我的“答案”不会被标记为正确的原因,我会等待 fastxml 团队修复它或解释如何正确使用此功能

标签: java android kotlin jackson


【解决方案1】:

在研究上浪费了一些时间后,我发现在AnnotatedFieldCollector#_findFields 中有一个调用JavaType.getRawClass().getDeclaredFields()for 块,如果它返回一个空数组,则跳过所有for 块,映射_fields未初始化并在调用_addFieldMixIns 时保持null

这是因为属性不是 kotlin 中的字段,并且父类没有字段。

可以通过将 @JvmField 带注释的属性添加到 NotificationEvent 类来解决此问题,如下所示:

sealed class NotificationEvent {

  @Suppress("unused")
  @JvmField val stub: Int = 0

  data class SomeUsefulEvent(val eventData: String): NotificationEvent()

}

一切正常!

我希望这个问题对某人有所帮助,我鼓励 Jackson 团队修复这个错误

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多