La sérialisation de la Carte avec Jackson

je veux sérialiser une Carte avec Jackson. La Date doit être sérialisée comme un horodatage, comme toutes mes autres dates.

le code suivant rend les clés sous la forme" Tue Mar 11 00:00:00 CET 1952 " (qui est Date.toString()) au lieu du timestamp.

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

je suppose que c'est à cause de type erasure et jackson ne sait pas à l'exécution que la clé est une Date. Mais je n'ai pas trouvé le moyen de passer une référence typographique à une méthode writeValue.

Est-il une façon simple d'obtenir le comportement désiré ou est-ce que toutes les clés sont toujours rendues comme des cordes par jackson?

Merci pour tout conseil.

27
demandé sur Florian Gutmann 2011-07-04 21:51:07

3 réponses

la clé de map par défaut serializer est StdKeySerializer, et il est tout simplement cela.

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

Vous pourriez faire usage de la fonctionnalité SimpleModule, et spécifiez un serialiseur de clés personnalisé, en utilisant le addKeySerializer méthode.


Et voici comment cela pourrait être fait.

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

mise à Jour pour la dernière 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()));
  }
}
41
répondu Programmer Bruce 2016-10-25 07:54:34

comme d'habitude, la réponse de Bruce est immédiate.

une pensée supplémentaire est que puisqu'il y a un paramètre global pour sérialiser les valeurs de Date en tant qu'horodatage (SerializationConfig.Caractéristique.WRITE_DATES_AS_TIMESTAMPS), peut-être que cela devrait s'appliquer ici aussi. Et / ou utilisez au moins le format ISO-8601 pour le texte. La principale question pratique est celle de la compatibilité ascendante; cependant, je doute que l'utilisation actuelle du simple toString() soit très utile car il n'est ni efficace ni pratique (lire la valeur).

donc, si vous voulez, vous pourriez vouloir déposer une requête de fonctionnalité; cela ressemble à une manipulation sous-optimale des clés de carte par Jackson.

4
répondu StaxMan 2011-07-05 19:24:41

Depuis Jackson 2.0 (peut-être 1.9, trop), WRITE_DATE_KEYS_AS_TIMESTAMPS peut être utilisé pour modifier ce comportement particulier.

exemple d'Utilisation ObjectMapper:

ObjectMapper m = new ObjectMapper().configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, true);

et ObjectWriter:

ObjectWriter w = mapper.with(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
1
répondu Roben 2015-11-26 12:53:16