Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson java.util.Date value in Map<String, Object> (de-)serialization

Consider this property

@JsonProperty
private Map<String, Object> myMap;

When a contained java.util.Date value is serialized as long, it will not be deserialized to Date again because the type information is not present in Map<String, Object>. How can I bypass the problem? I read answers about this question which would be a work around but there would be no way to distinguish strings containing dates from dates serialized as strings in the map. Can I tell Jackson to include type information for each map value such that Jackson can deserialize them correctly?

like image 585
Steffen Harbich Avatar asked Mar 15 '18 14:03

Steffen Harbich


People also ask

How does Jackson serialize date?

It's important to note that Jackson will serialize the Date to a timestamp format by default (number of milliseconds since January 1st, 1970, UTC).

What is Jackson Object serialization?

Jackson is a solid and mature JSON serialization/deserialization library for Java. The ObjectMapper API provides a straightforward way to parse and generate JSON response objects with a lot of flexibility.

Does Jackson use Java serialization?

XML Serialization and Deserialization with Jackson This short tutorial shows how the Jackson library can be used to serialize Java object to XML and deserialize them back to objects.

How do you serialize a map Object in Java?

We are using writeObject() method of ObjectOutputStream to serialize HashMap in Java. In the following program, we save the hashmap content in a serialized newHashMap file. Once you run the following code, a newHashMap file will be created. This file is used for deserialization in the next upcoming program.


1 Answers

Implement a custom Deserializer and add the Annotation @JsonDeserialize(using = DateDeserializer.class) to your field.

Take a look at this example:

Your Json-Bean:

public class Foo {

    private String            name;

    @JsonProperty
    @JsonDeserialize(using = DateDeserializer.class)
    private Map<String, Object> dates;

    [...] // getter, setter, equals, hashcode
}

Deserializer:

public class DateDeserializer extends JsonDeserializer<Map<String, Object>> {

    private TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {};

    @Override
    public Map<String, Object> deserialize(JsonParser p, DeserializationContext ctxt, Map<String, Object> target) throws IOException, JsonProcessingException {

        Map<String, Long> map = new ObjectMapper().readValue(p, typeRef);

        for(Entry<String, Long> e : map.entrySet()){

            Long value = e.getValue();
            String key = e.getKey();

            if(value instanceof Long){ // or if("date".equals(key)) ...
                target.put(key, new Date(value));
            } else {
                target.put(key, value); // leave as is
            }

        }

        return target;
    }

    @Override
    public Map<String, Object> deserialize(JsonParser paramJsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return this.deserialize(paramJsonParser, ctxt, new HashMap<>());
    }

}

Simple test:

public static void main(String[] args) throws Exception {

    Foo foo1 = new Foo();
    foo1.setName("foo");
    foo1.setData(new HashMap<String, Object>(){{
        put("date",   new Date());
        put("bool",   true);
        put("string", "yeah");
    }});
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = mapper.writeValueAsString(foo1);
    System.out.println(jsonStr);
    Foo foo2 = mapper.readValue(jsonStr, Foo.class);

    System.out.println(foo2.equals(foo1));

}
like image 160
dieter Avatar answered Sep 23 '22 14:09

dieter