即使使用 NON_NULL,Jackson ObjectMapper 也会抛出 NullPointerException
Posted
技术标签:
【中文标题】即使使用 NON_NULL,Jackson ObjectMapper 也会抛出 NullPointerException【英文标题】:Jackson ObjectMapper throwing NullPointerException even with NON_NULL 【发布时间】:2016-08-13 18:47:46 【问题描述】:当使用以下 JSON 并且“phones”或“emailAddresses”为空时,我会收到 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里面是一个User对象,里面包含List和List。这些难道不应该根据对象映射器配置进行序列化吗?
【问题讨论】:
Caused by: java.lang.NullPointerException at com.test.User.setPhones(User.java:202)
@Rocki 但是,当映射器配置为忽略 NULL 值时,为什么还要尝试使用设置器呢?它不考虑等级较低的类吗?
setSerializationInclusion 只会忽略 serialization 而不是 deserialization 的 null 值。您可以让您的用户模型知道空值或使用自定义JsonNodeDeserializer
并覆盖public JsonNode getNullValue()
。
【参考方案1】:
根据 Rocki 的评论:
setSerializationInclusion 只会忽略空值 序列化不是反序列化。
如果传入的“电话”值在我的用户类中为空,我没有处理,所以它正在抛出 NPE。我已经更新以确认它不为空。如果是,它会在任何其他逻辑之前短路:
/**
* @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;
【讨论】:
我记得仔细阅读了堆栈跟踪。谢谢。【参考方案2】:我想知道 phones
属性是否实际存在于您的 JSON 中,这是否意味着您的映射器没有将其视为 NON_NULL (即它没有丢失,它存在但您给它的值是 @ 987654322@ 明确)
尝试改用JsonInclude.Include.NON_DEFAULT
。
如果失败了,您是否尝试过在类上使用注释而不是 this.setSerializationInclusion()?
@JsonInclude(Include.NON_DEFAULT)
public class MigrationObjectMapper
....
【讨论】:
以上是关于即使使用 NON_NULL,Jackson ObjectMapper 也会抛出 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
Jackson 包含 non_null 不能处理来自 kotlin 扩展函数的对象
@JsonInclude(Include.NON_NULL)
@JsonInclude(Include.NON_NULL)