次のJSONが使用され、「phones」または「emailAddresses」のいずれかがnullの場合、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": []
}
_
そしてここにスタックトレースがあります:
_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
_
私は次のようにカスタムObjectMapperを設定しています:
_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();
}
}
_
つまり、CteUserContext cteUserContext = MigrationObjectMapper.getMigrationObjectMapper().convertValue(item.getItem(), new TypeReference<CteUserContext>(){});
がエラーをスローしています。
CteUserContext内には、ListとListを含むUserオブジェクトがあります。これらはオブジェクトマッパーの構成に基づいてシリアル化されるべきではありませんか?
ロッキーのコメント:
setSerializationInclusionは、逆シリアル化ではなくシリアル化の場合にのみnull値を無視します。
着信する「電話」の値がユーザークラスでnullの場合は処理しなかったため、NPEがスローされていました。 nullではないことを確認するために更新しました。もしそうなら、それは他のロジックの前に短絡します:
/**
* @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;
}
phones
プロパティが実際にJSONに存在するという事実は、マッパーがそれをNON_NULLとして処理していないことを意味します(つまり、欠落していないのではなく、そこにありますが、null
の値を明示的に指定しています)。
代わりにJsonInclude.Include.NON_DEFAULT
を使用してみてください。
それが失敗した場合、this.setSerializationInclusion()の代わりにクラスのアノテーションを使用してみましたか?
@JsonInclude(Include.NON_DEFAULT)
public class MigrationObjectMapper {
....
}