2 votes

Jackson android NPE lors de l'utilisation de MixIn

Mon api de serveur utilise des objets polymorphes de différents types. Par exemple, j'ai un json :

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

et la classe kotlin correspondante :

sealed class NotificationEvent {

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

}

et la classe mixin :

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

lorsque j'appelle côté client

jsonMapper.readValue(event.data)

l'application plante avec une NPE :

java.lang.NullPointerException: Tentative d'invocation de la méthode de l'interface 'java.lang.Object java.util.Map.get(java.lang.Object)' sur une référence d'objet null at com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector._addFieldMixIns(AnnotatedFieldCollector.java:110) at com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector._findFields(AnnotatedFieldCollector.java:87) at com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector.collect(AnnotatedFieldCollector.java:41) at com.fasterxml.jackson.databind.introspect.AnnotatedFieldCollector.collectFields(AnnotatedFieldCollector.java:36) at com.fasterxml.jackson.databind.introspect.AnnotatedClass._fields(AnnotatedClass.java:349) at com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:321) at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:379) at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:308) at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:287) at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:170) at com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164) at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239) at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:346) at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:330) at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:255) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:214) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137) at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:411) at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349) at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264) at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244) at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142) at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:477) at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4178) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3997) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3011)

comment puis-je éviter ce crash ?

0voto

Après avoir gaspillé un certain temps en recherches, j'ai découvert que dans AnnotatedFieldCollector#_findFields, il y a un bloc for qui appelle JavaType.getRawClass().getDeclaredFields() et si cela renvoie un tableau vide, tout le bloc for est ignoré, la carte _fields n'est pas initialisée et reste null lorsque _addFieldMixIns est appelé.

Cela arrive parce que les propriétés ne sont pas des champs en kotlin et la classe parent n'en a pas.

Ce problème peut être contourné en ajoutant une propriété annotée @JvmField à la classe NotificationEvent comme ceci:

sealed class NotificationEvent {

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

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

}

et tout fonctionne correctement!

J'espère que cette question aidera quelqu'un et j'encourage l'équipe de Jackson à corriger ce bug

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X