7

I'm trying to deserialize a JSON string into a ConcurrentHashMap object and I'm getting errors because my JSON contains properties with null values, but ConcurrentHashMap does not accept null values. Here is the fragment of code:

ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonString, ConcurrentHashMap.class);

Is there a way to ignore properties with null values during deserialization? I know that we can ignore these properties during serialization:

mapper.setSerializationInclusion(JsonInclude.NON_NULL);

But what about deserialization process?

Radu Dumbrăveanu
  • 1,266
  • 1
  • 22
  • 32
  • unfortunately this post is only about suppressing properties during serializing, but I'm interested in the opposite process: suppressing properties during deserializing. – Radu Dumbrăveanu Aug 28 '15 at 12:03
  • I think the best way is to exclude NULL values during the creation phase of the json. By this way you would not care about it at all. – Anastasios Vlasopoulos Aug 28 '15 at 12:11

2 Answers2

3

There may be a better way but a workaround would be:

Map<String, Object> map = mapper.readValue(jsonString, HashMap.class);
map.values().removeIf(o -> o == null);
return new ConcurrentHashMap<> (map);
assylias
  • 321,522
  • 82
  • 660
  • 783
  • I have to use ConcurrentHashMap because of Sonar. The answer is perfect, but I can not use Map, only ConcurrentMap. – Radu Dumbrăveanu Aug 28 '15 at 12:21
  • @RaduDumbrăveanu It makes no difference functionally - your map is not accessible to external code until you return, so whether it is concurrent or not at deserialisation time is irrelevant... Unless you find a better way, I would just use that solution and tell Sonar to ignore the problem. – assylias Aug 28 '15 at 13:13
1

The following trick has worked for me:

ObjectMapper mapper = new ObjectMapper();

String jsonString = "{\"key1\": 1, \"key2\": null, \"key3\": 3}";

ConcurrentHashMap<String, Object> map = mapper.readValue(jsonString, new ConcurrentHashMap<String, Object>() {
    @Override
    public Object put(String key, Object value) {
        return value != null ? super.put(key, value) : null;
    }
}.getClass());

System.out.println(map); // {key1=1, key3=3}

The idea is to simply override ConcurrentHashMap.put() method so that it ignores null values that are to be added to the map.

Instead of an anonymous inner class, you could create your own class that extends from ConcurrentHashMap:

public class NullValuesIgnorerConcurrentHashMap<K, V>
    extends ConcurrentHashMap<K, V> {

    @Override
    public V put(K key, V value) {
        return value != null ? super.put(key, value) : null;
    }
}

Then you would use this class to deserialize to a ConcurrentHashMap:

ConcurrentHashMap<String, Object> map = 
    mapper.readValue(jsonString, NullValuesIgnorerConcurrentHashMap.class);

System.out.println(map); // {key1=1, key3=3}

With this approach, the returned map would never throw NullPointerException on put() when given a null value.

fps
  • 33,623
  • 8
  • 55
  • 110
  • I have try your solution, but it not work for me. I need to use `mapper.readValue(jsonString, new TypeReference>() { });` to create a map from JSON data. – theShadow89 Jan 03 '17 at 23:55
  • @theShadow89 Maybe you could use `mapper.readValue(jsonString, new TypeReference>() { }`, as the `NullValuesIgnorerConcurrentHashMap` type is generic. – fps Jan 04 '17 at 03:09