Java 即使使用 NON_NULL,Jackson ObjectMapper 也会抛出 NullPointerException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36754835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:38:33  来源:igfitidea点击:

Hymanson ObjectMapper throwing NullPointerException even with NON_NULL

javajsonnullpointerexceptionHymansonobjectmapper

提问by ev0lution37

When the following JSON is used and either "phones" or "emailAddresses" are null, I'm getting a NullPointerException.

当使用以下 JSON 并且“电话”或“电子邮件地址”为空时,我收到 NullPointerException。

JSON:

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": []
}

And here's the stacktrace:

这是堆栈跟踪:

Exception in thread "main" com.fasterxml.Hymanson.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.Hymanson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:510)
    at com.fasterxml.Hymanson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:493)
    at com.fasterxml.Hymanson.databind.deser.impl.MethodProperty.set(MethodProperty.java:116)
    at com.fasterxml.Hymanson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
    at com.fasterxml.Hymanson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:464)
    at com.fasterxml.Hymanson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
    at com.fasterxml.Hymanson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:464)
    at com.fasterxml.Hymanson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295)
    at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
    at com.fasterxml.Hymanson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
    at com.fasterxml.Hymanson.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.Hymanson.databind.deser.impl.MethodProperty.set(MethodProperty.java:114)
    ... 19 more

I'm setting up my custom ObjectMapper like this:

我正在像这样设置我的自定义 ObjectMapper:

package com.test;

import com.fasterxml.Hymanson.annotation.JsonInclude;
import com.fasterxml.Hymanson.databind.DeserializationFeature;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.databind.SerializationFeature;
import com.fasterxml.Hymanson.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();
    }
}

Which means CteUserContext cteUserContext = MigrationObjectMapper.getMigrationObjectMapper().convertValue(item.getItem(), new TypeReference<CteUserContext>(){});is throwing the error.

这意味着CteUserContext cteUserContext = MigrationObjectMapper.getMigrationObjectMapper().convertValue(item.getItem(), new TypeReference<CteUserContext>(){});抛出错误。

Inside CteUserContext is a User object, which contains List and List. Shouldn't these just not be serialized based on the object mapper configuration?

CteUserContext 里面是一个 User 对象,它包含 List 和 List。这些不应该根据对象映射器配置进行序列化吗?

采纳答案by ev0lution37

Per Rocki's comment:

根据 Rocki 的评论:

setSerializationInclusion will ignore null values only for serialization not deserialization.

setSerializationInclusion 将仅在序列化而不是反序列化时忽略空值。

I wasn't handling if the incoming "phones" value was null in my User class, so it was throwing the NPE. I've updated to confirm that it isn't null. If it is, it'll short circuit before any other logic:

如果传入的“电话”值在我的 User 类中为空,我没有处理,所以它抛出了 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;
} 

回答by Brad

I'm wondering whether the fact that the phonesproperty is actually present in your JSON, means your mapper is not treating it as NON_NULL (i.e. it's not missing, it is there but you have given it a value of nullexplicitly)

我想知道该phones属性实际上存在于您的 JSON 中这一事实是否意味着您的映射器没有将其视为 NON_NULL(即它没有丢失,它在那里,但您已经null明确地给了它一个值)

Try using JsonInclude.Include.NON_DEFAULTinstead.

尝试使用JsonInclude.Include.NON_DEFAULT

Failing that, have you tried using the annotation on the class instead of this.setSerializationInclusion()?

如果失败,您是否尝试过在类上使用注释而不是 this.setSerializationInclusion()?

@JsonInclude(Include.NON_DEFAULT)
public class MigrationObjectMapper {
    ....
}