Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing Map<Date, String> with Jackson

I want to serialize a Map with Jackson. The Date should be serialized as a timestamp, like all my other dates.

The following code renders the keys in the form "Tue Mar 11 00:00:00 CET 1952" (which is Date.toString()) instead of the timestamp.

Map<Date, String> myMap = new HashMap<Date, String>(); ... ObjectMapper.writeValue(myMap) 

I assume this is because of type erasure and jackson doesn't know at runtime that the key is a Date. But I didn't find a way to pass a TypeReference to any writeValue method.

Is there a simple way to achieve my desired behaviour or are all keys always rendered as Strings by jackson?

Thanks for any hint.

like image 978
Florian Gutmann Avatar asked Jul 04 '11 17:07

Florian Gutmann


People also ask

How does Jackson deserialize dates from JSON?

How to deserialize Date from JSON using Jackson. In order to correct deserialize a Date field, you need to do two things: 1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method.

How do I change the date format in ObjectMapper?

We can format a date using the setDateFormat() of ObjectMapper class. This method can be used for configuring the default DateFormat when serializing time values as Strings and deserializing from JSON Strings.

Does Jackson use Java serialization?

Note that Jackson does not use java.

What is Jackson datatype JSR310 used for?

As already mentioned, Jackson-Datatype-JSR310 provides support for Java 8 Time. You have to register the module like this: ObjectMapper mapper = new ObjectMapper(); mapper.


1 Answers

The default map key serializer is StdKeySerializer, and it simply does this.

String keyStr = (value.getClass() == String.class) ? ((String) value) : value.toString(); jgen.writeFieldName(keyStr); 

You could make use of the SimpleModule feature, and specify a custom key serializer, using the addKeySerializer method.


And here's how that could be done.

import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map;  import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.Version; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.module.SimpleModule; import org.codehaus.jackson.map.type.MapType; import org.codehaus.jackson.map.type.TypeFactory;  public class CustomKeySerializerDemo {   public static void main(String[] args) throws Exception   {     Map<Date, String> myMap = new HashMap<Date, String>();     myMap.put(new Date(), "now");     Thread.sleep(100);     myMap.put(new Date(), "later");      ObjectMapper mapper = new ObjectMapper();     System.out.println(mapper.writeValueAsString(myMap));     // {"Mon Jul 04 11:38:36 MST 2011":"now","Mon Jul 04 11:38:36 MST 2011":"later"}      SimpleModule module =         new SimpleModule("MyMapKeySerializerModule",             new Version(1, 0, 0, null));     module.addKeySerializer(Date.class, new DateAsTimestampSerializer());      MapType myMapType = TypeFactory.defaultInstance().constructMapType(HashMap.class, Date.class, String.class);      ObjectWriter writer = new ObjectMapper().withModule(module).typedWriter(myMapType);     System.out.println(writer.writeValueAsString(myMap));     // {"1309806289240":"later","1309806289140":"now"}   } }  class DateAsTimestampSerializer extends JsonSerializer<Date> {   @Override   public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)        throws IOException, JsonProcessingException   {     jgen.writeFieldName(String.valueOf(value.getTime()));   } } 

Update for the latest Jackson (2.0.4):

import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map;  import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory;  public class CustomKeySerializerDemo {   public static void main(String[] args) throws Exception   {     Map<Date, String> myMap = new HashMap<Date, String>();     myMap.put(new Date(), "now");     Thread.sleep(100);     myMap.put(new Date(), "later");      ObjectMapper mapper = new ObjectMapper();     System.out.println(mapper.writeValueAsString(myMap));     // {"2012-07-13T21:14:09.499+0000":"now","2012-07-13T21:14:09.599+0000":"later"}      SimpleModule module = new SimpleModule();     module.addKeySerializer(Date.class, new DateAsTimestampSerializer());      MapType myMapType = TypeFactory.defaultInstance().constructMapType(HashMap.class, Date.class, String.class);      ObjectWriter writer = new ObjectMapper().registerModule(module).writerWithType(myMapType);     System.out.println(writer.writeValueAsString(myMap));     // {"1342214049499":"now","1342214049599":"later"}   } }  class DateAsTimestampSerializer extends JsonSerializer<Date> {   @Override   public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)        throws IOException, JsonProcessingException   {     jgen.writeFieldName(String.valueOf(value.getTime()));   } } 
like image 190
Programmer Bruce Avatar answered Sep 18 '22 08:09

Programmer Bruce