Jackson ObjectMapper throwing NullPointerException even with NON_NULL

33,314

Solution 1

Per Rocki's comment:

setSerializationInclusion will ignore null values only for serialization not deserialization.

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:

/**
 * @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;
} 

Solution 2

I'm wondering whether the fact that the phones property 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 null explicitly)

Try using JsonInclude.Include.NON_DEFAULT instead.

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

@JsonInclude(Include.NON_DEFAULT)
public class MigrationObjectMapper {
    ....
}
Share:
33,314
ev0lution37
Author by

ev0lution37

Updated on September 01, 2020

Comments

  • ev0lution37
    ev0lution37 over 3 years

    When the following JSON is used and either "phones" or "emailAddresses" are null, I'm getting a 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": []
    }
    

    And here's the 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
    

    I'm setting up my custom ObjectMapper like this:

    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();
        }
    }
    

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

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

  • Monday Fatigue
    Monday Fatigue over 2 years
    I remembered to read the stack trace carefully. Thank you.