Sérialisation et désérialisation de cartes avec Jackson

Sérialisation et désérialisation de cartes avec Jackson

1. Vue d'ensemble

Dans cet article, nous examineronsserialization and deserialization of Java maps using Jackson.

Nous allons illustrer comment sérialiser et désérialiserMap<String, String>,Map<Object, String>, etMap<Object, Object> vers et depuis lesStrings. au format JSON

2. Configuration Maven


    com.fasterxml.jackson.core
    jackson-databind
    2.9.4

Vous pouvez obtenir la dernière version de Jacksonhere.

3. La sérialisation

La sérialisation convertit un objet Java en un flux d'octets, qui peuvent être persistés ou partagés si nécessaire. JavaMaps sont des collections qui mappent une cléObject à une valeurObject et sont souvent les objets les moins intuitifs à sérialiser.

3.1. SérialisationMap<String, String>

Pour le cas simple, créons unMap<String, String> et sérialisons-le en JSON:

Map map = new HashMap<>();
map.put("key", "value");

ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

ObjectMapper est le mappeur de sérialisation de Jackson, qui nous permet de sérialiser nosmap et de l'écrire comme un joli JSONString, en utilisant la méthodetoString() dansString:

{
  "key" : "value"
}

3.2. SérialisationMap<Object, String>

Vous pouvez sérialiser une carte contenant une classe Java personnalisée en quelques étapes supplémentaires. Créons une classeMyPair pour représenter une paire d’objetsString associés.

Remarque: les getters / setters doivent être publics, et nous annotonstoString() avec@JsonValue pour nous assurer que Jackson utilise cestoString() personnalisés lors de la sérialisation:

public class MyPair {

    private String first;
    private String second;

    @Override
    @JsonValue
    public String toString() {
        return first + " and " + second;
    }

    // standard getter, setters, equals, hashCode, constructors
}

Voyons maintenant à Jackson comment sérialiserMyPair en étendant lesJsonSerializer de Jackson:

public class MyPairSerializer extends JsonSerializer {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public void serialize(MyPair value,
      JsonGenerator gen,
      SerializerProvider serializers)
      throws IOException, JsonProcessingException {

        StringWriter writer = new StringWriter();
        mapper.writeValue(writer, value);
        gen.writeFieldName(writer.toString());
    }
}

JsonSerializer, comme son nom l'indique, sérialiseMyPair en JSON à l'aide de la méthodetoString() deMyPair. Jackson fournit de nombreuxSerializer classes pour répondre à vos besoins de sérialisation.

Nous appliquonsMyPairSerializer à nosMap<MyPair, String> avec l'annotation@JsonSerialize. Notez que nous avons seulement dit à Jackson comment sérialiserMyPair car il sait déjà comment sérialiserString:

@JsonSerialize(keyUsing = MyPairSerializer.class)
Map map;

Testons notre sérialisation de carte:

map = new HashMap<>();
MyPair key = new MyPair("Abbott", "Costello");
map.put(key, "Comedy");

String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

La sortie JSON sérialisée est:

{
  "Abbott and Costello" : "Comedy"
}

3.3. SérialisationMap<Object, Object>

Le cas le plus complexe est la sérialisation d'unMap<Object, Object>, mais l'essentiel du travail est déjà fait. Utilisons lesMapSerializer de Jackson pour notre carte et lesMyPairSerializer de la section précédente pour les types de clé et de valeur de la carte:

@JsonSerialize(keyUsing = MapSerializer.class)
Map map;

@JsonSerialize(keyUsing = MyPairSerializer.class)
MyPair mapKey;

@JsonSerialize(keyUsing = MyPairSerializer.class)
MyPair mapValue;

Testons la sérialisation de nosMap<MyPair, MyPair>:

mapKey = new MyPair("Abbott", "Costello");
mapValue = new MyPair("Comedy", "1940s");
map.put(mapKey, mapValue);

String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

La sortie JSON sérialisée, utilisant la méthodetoString() deMyPair, est la suivante:

{
  "Abbott and Costello" : "Comedy and 1940s"
}

4. Désérialisation

La désérialisation convertit un flux d'octets en un objet Java que nous pouvons utiliser dans le code. Dans cette section, nous désérialiserons l'entrée JSON enMaps de signatures différentes.

4.1. DésérialisationMap<String, String>

Pour le cas simple, prenons une chaîne d'entrée au format JSON et convertissons-la en une collection JavaMap<String, String>:

String jsonInput = "{\"key\": \"value\"}";
TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

Nous utilisons lesObjectMapper de Jackson comme nous l'avons fait pour la sérialisation, en utilisantreadValue() pour traiter l'entrée. Notez également que nous utilisons lesTypeReference de Jackson, que nous utiliserons dans tous nos exemples de désérialisation, pour décrire le type de notre destinationMap. Voici la représentationtoString() de notre carte:

{key=value}

4.2. DésérialisationMap<Object, String>

Maintenant, changeons notre entrée JSON et lesTypeReference de notre destination enMap<MyPair, String>:

String jsonInput = "{\"Abbott and Costello\" : \"Comedy\"}";

TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

Nous devons créer un constructeur pourMyPair qui prend unString avec les deux éléments et les analyse en élémentsMyPair:

public MyPair(String both) {
    String[] pairs = both.split("and");
    this.first = pairs[0].trim();
    this.second = pairs[1].trim();
}

Et letoString() de notre objetMap<MyPair,String> est:

{Abbott and Costello=Comedy}

There is another option for the case when we deserialize into a Java class that contains a Map — we can use Jackson’s KeyDeserializer class, l'une des nombreuses classesDeserialization proposées par Jackson. Nous annotons nosClassWithAMap avec@JsonCreator,@JsonProperty et@JsonDeserialize:

public class ClassWithAMap {

  @JsonProperty("map")
  @JsonDeserialize(keyUsing = MyPairDeserializer.class)
  private Map map;

  @JsonCreator
  public ClassWithAMap(Map map) {
    this.map = map;
  }

  // public getters/setters omitted
}

Nous disons à Jackson de désérialiser lesMap<MyPair, String> contenus dansClassWithAMap, nous devons donc étendreKeyDeserializer pour décrire comment désérialiser la clé de la carte, un objetMyPair, à partir d'une entrée String:

public class MyPairDeserializer extends KeyDeserializer {

  @Override
  public MyPair deserializeKey(
    String key,
    DeserializationContext ctxt) throws IOException,
    JsonProcessingException {

      return new MyPair(key);
    }
}

Nous testons la désérialisation en utilisantreadValue:

String jsonInput = "{\"Abbott and Costello\":\"Comedy\"}";

ClassWithAMap classWithMap = mapper.readValue(jsonInput,
  ClassWithAMap.class);

Encore une fois, la méthodetoString() de notre carteClassWithAMap’s nous donne le résultat attendu:

{Abbott and Costello=Comedy}

4.3. DésérialisationMap<Object,Object>

Enfin, changeons notre entrée JSON et lesTypeReference de notre destination enMap<MyPair, MyPair>:

String jsonInput = "{\"Abbott and Costello\" : \"Comedy and 1940s\"}";
TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

Et letoString() de notre objetMap<MyPair, MyPair> est:

{Abbott and Costello=Comedy and 1940s}

5. Conclusion

Dans ce rapide tutoriel, nous avons vu comment sérialiser et désérialiser JavaMaps vers et depuis des chaînes au format JSON.

Comme toujours, vous pouvez consulter l'exemple fourni dans cet article dans lesGithub repository.