Lorsque le code JSON suivant est utilisé et que "phones" ou "emailAddresses" ont la valeur null, je reçois une exception NullPointerException.
JSON:
{
"item": {
"messages": {
"user.phone.missing": {
"type": "warning",
"key": "user.phone.missing",
"message": "User profile does not have a phone number",
"code": null
},
"user.email.missing": {
"type": "warning",
"key": "user.email.missing",
"message": "User profile does not have an email address",
"code": null
},
"user.es.sync.failed": {
"type": "error",
"key": "user.es.sync.failed",
"message": "Unable to sync user",
"code": null
}
},
"user": {
"firstName": "Test",
"middleInitial": null,
"lastName": "User",
"createdDt": "2016-04-20 19:50:03+0000",
"updatedDt": null,
"lastVerifiedDt": null,
"status": "DEACTIVATED",
"tokens": [
{
"tokenHash": "test hash",
"tokenValue": "test dn",
"createdDt": "2016-04-20 19:50:03+0000",
"updatedDt": null,
"status": "ENABLED"
}
],
"phones": null,
"emailAddresses": null
}
},
"status": "SUCCESS",
"errors": []
}
Et voici le stacktrace:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: N/A (through reference chain: com.test.message.cte.CteItemResponse["item"]->com.test.message.cte.CteUserContext["user"]->com.test.User["phones"])
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.Java:510)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.Java:493)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.set(MethodProperty.Java:116)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.Java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.Java:295)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:121)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.Java:464)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.Java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.Java:295)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:121)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.Java:464)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.Java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.Java:295)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.Java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.Java:2041)
at com.test.Test.main(Test.Java:20)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.Java:144)
Caused by: Java.lang.NullPointerException
at com.test.User.setPhones(User.Java:202)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:498)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.set(MethodProperty.Java:114)
... 19 more
Je configure mon ObjectMapper personnalisé comme ceci:
package com.test;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
public class MigrationObjectMapper extends ObjectMapper {
private MigrationObjectMapper() {
// do not serialize null value fields
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public static MigrationObjectMapper getMigrationObjectMapper(){
return new MigrationObjectMapper();
}
}
Ce qui signifie que CteUserContext cteUserContext = MigrationObjectMapper.getMigrationObjectMapper().convertValue(item.getItem(), new TypeReference<CteUserContext>(){});
renvoie l'erreur.
Inside CteUserContext est un objet User, qui contient List et List. Ne devraient-ils pas simplement être sérialisés en fonction de la configuration du mappeur d'objets?
Commentaire de Per Rocki:
setSerializationInclusion ignorera les valeurs NULL uniquement pour la sérialisation non la désérialisation.
Je ne gérais pas si la valeur "phones" entrants était nulle dans ma classe User, elle renvoyait donc le NPE. J'ai mis à jour pour confirmer que ce n'est pas nul. Si c'est le cas, il court-circuiter toute autre logique:
/**
* @param phones The phones
*/
@JsonProperty("phones")
public void setPhones(List<Phone> phones) {
if ((phones != null) && (phones.size() > 1)) {
int primaryIndex = -1;
Phone primaryPhone = null;
for (Phone p : phones) {
if (p.getIsPrimary()) {
primaryIndex = phones.indexOf(p);
primaryPhone = p;
break;
}
}
phones.remove(primaryIndex);
phones.add(0, primaryPhone);
}
this.phones = phones;
}
Je me demande si le fait que la propriété phones
soit réellement présente dans votre code JSON signifie que votre mappeur ne la traite pas comme étant NON_NULL (c'est-à-dire qu'il ne manque pas, il est présent mais vous lui avez explicitement attribué la valeur null
)
Essayez d'utiliser JsonInclude.Include.NON_DEFAULT
à la place.
Sinon, avez-vous essayé d'utiliser l'annotation sur la classe à la place de this.setSerializationInclusion ()?
@JsonInclude(Include.NON_DEFAULT)
public class MigrationObjectMapper {
....
}