7

I'm using Jackson to deserialize a JSON that could contain null values for Map variables. What I want is if the value is null, I want the map to be an empty HashMap instead of null.

JSON:

{"names":null, "descriptions":null, "nicknames":null...}

Java class:

private User {
    private Map<String,String> names = new HashMap<>();
    private Map<String,String> descriptions = new HashMap<>();
    private Map<String,String> nicknames = new HashMap<>();
}

Right now when the ObjectMapper deserializes the JSON, it overrides the fields, and sets names, descriptions, and nicknames as null.

Is there a a generic way so I would not have to add code each time I have a new map property?

Glide
  • 20,235
  • 26
  • 86
  • 135

3 Answers3

6

Add a setter for your map:

public void setNames(Map<String, String> names) {
    this.names = (names == null) ? new HashMap<>() : names;
}

This setter will be detected by Jackson and will be used when the property is read from the JSON. So within your setter, you can check if the value is null, and if it is then you create a new HashMap.

Simon Forsberg
  • 13,086
  • 10
  • 64
  • 108
  • 1
    Or, more tersely, `this.names = (names == null) ? new HashMap<>() : names;` – or if you have Guava, `Objects.firstNonNull()`. – Matt Ball Nov 08 '13 at 19:29
  • @MattBall Thanks, I was just about to edit and improve that part :) – Simon Forsberg Nov 08 '13 at 19:31
  • Is there a way to do it in a generic way to I would not have to add code each time I have a new map in a property? – Glide Nov 08 '13 at 19:34
  • @Glide You could attempt creating your own Map-deserializer, but I'm not sure that's something I would recommend in this case. You could also call a method on your object after you have deserialized it, to create new HashMaps for the properties that were null. – Simon Forsberg Nov 08 '13 at 19:43
6

You can setup you own module and override getNullValue()

see doc http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/map/JsonDeserializer.html

Note

I register the Deserializer for all Map.class, not so exact

test code

    SimpleModule module = new SimpleModule("test",  new Version(1, 0, 0, null));

    module.addDeserializer(Map.class, new JsonDeserializer<Map>() {
        @Override
        public Map deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            return jp.readValueAs(HashMap.class);
        }

        @Override
        public Map getNullValue() {
            return new HashMap();
        }
    });

    mapper.registerModule(module);

test case

String s = "{\"names\":{\"1\":2}, \"descriptions\":null, \"nicknames\":null}";

result

User{descriptions={}, names={1=2}, nicknames={}}
farmer1992
  • 7,816
  • 3
  • 30
  • 26
1

With recently released Jackson 2.3.0, there is a new option:

public class POJO {
   @JsonSerialize(nullsUsing=MyNullSerializer.class)
   public Map<String,Object> stuff;
}

so that you can define custom serialize that is only used for serializing null value of given property as any valid JSON value (note that it can not be used to "not write anything", since it does not control writing of property name).

StaxMan
  • 113,358
  • 34
  • 211
  • 239