Intro à Jackson ObjectMapper

Introduction à l'ObjectMapper de Jackson

1. Vue d'ensemble

Cet article se concentre sur la compréhension de la classe JacksonObjectMapper - et sur la façon de sérialiser des objets Java en JSON et de désérialiser la chaîne JSON en objets Java. Pour en savoir plus sur la bibliothèque Jackson en général, leJackson Tutorial est un bon point de départ.

Lectures complémentaires:

Héritage avec Jackson

Ce tutoriel montrera comment gérer l'inclusion de métadonnées de sous-type et ignorer les propriétés héritées des super-classes avec Jackson.

Read more

Vues Jackson JSON

Comment utiliser l'annotation @JsonView dans Jackson pour contrôler parfaitement la sérialisation de vos objets (sans et avec Spring).

Read more

Jackson - Sérialiseur personnalisé

Contrôlez votre sortie JSON avec Jackson 2 à l'aide d'un sérialiseur personnalisé.

Read more

2. Les dépendances

Ajoutons d'abord les dépendances suivantes auxpom.xml:


    com.fasterxml.jackson.core
    jackson-databind
    2.9.8

Cette dépendance ajoutera également de manière transitoire les bibliothèques suivantes au chemin de classe:

  1. jackson-annotations-2.9.8.jar

  2. jackson-core-2.9.8.jar

  3. jackson-databind-2.9.8.jar

Utilisez toujours les dernières versions sur le référentiel central Maven pourJackson databind.

3. Lecture et écriture avecObjectMapper

Commençons par les opérations de base de lecture et d’écriture.

The simple readValue API of the ObjectMapper is a good entry point. Nous pouvons l'utiliser pour analyser ou désérialiser le contenu JSON dans un objet Java.

De plus, du côté de l'écriture,we can use the writeValue API to serialize any Java object as JSON output.

Nous utiliserons la classeCar suivante avec deux champs comme objet pour sérialiser ou désérialiser tout au long de cet article:

public class Car {

    private String color;
    private String type;

    // standard getters setters
}

3.1. Objet Java en JSON

Voyons un premier exemple de sérialisation d'un objet Java en JSON à l'aide de la méthodewriteValue de la classeObjectMapper:

ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
objectMapper.writeValue(new File("target/car.json"), car);

La sortie de ce qui précède dans le fichier sera:

{"color":"yellow","type":"renault"}

Les méthodeswriteValueAsString etwriteValueAsBytes de la classeObjectMapper génèrent un JSON à partir d'un objet Java et retourne le JSON généré sous forme de chaîne ou de tableau d'octets:

String carAsString = objectMapper.writeValueAsString(car);

3.2. JSON vers un objet Java

Vous trouverez ci-dessous un exemple simple de conversion d'une chaîne JSON en objet Java à l'aide de la classeObjectMapper:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);

La fonctionreadValue() accepte également d'autres formes d'entrée comme un fichier contenant une chaîne JSON:

Car car = objectMapper.readValue(new File("src/test/resources/json_car.json"), Car.class);

ou une URL:

Car car = objectMapper.readValue(new URL("file:src/test/resources/json_car.json"), Car.class);

3.3. JSON vers JacksonJsonNode

Alternativement, un JSON peut être analysé dans un objetJsonNode et utilisé pour récupérer des données à partir d'un nœud spécifique:

String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
// Output: color -> Black

3.4. Création d'une liste Java à partir d'une chaîne de tableau JSON

Nous pouvons analyser un JSON sous la forme d'un tableau dans une liste d'objets Java en utilisant unTypeReference:

String jsonCarArray =
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
List listCar = objectMapper.readValue(jsonCarArray, new TypeReference>(){});

3.5. Création d'une carte Java à partir d'une chaîne JSON

De même, nous pouvons analyser un JSON en un JavaMap:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Map map
  = objectMapper.readValue(json, new TypeReference>(){});

4. Fonctionnalités avancées

L'une des plus grandes forces de la bibliothèque de Jackson est le processus de personnalisation et de désérialisation hautement personnalisable.

Dans cette section, nous allons passer en revue certaines fonctionnalités avancées dans lesquelles la réponse JSON d'entrée ou de sortie peut être différente de l'objet qui génère ou consomme la réponse.

4.1. Configuration de la fonctionnalité de sérialisation ou de désérialisation

Lors de la conversion d'objets JSON en classes Java, si la chaîne JSON comporte de nouveaux champs, le processus par défaut générera une exception:

String jsonString
  = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";

La chaîne JSON dans l'exemple ci-dessus dans le processus d'analyse par défaut de l'objet Java pour lesClass Car entraînera l'exceptionUnrecognizedPropertyException.

Grâce à la méthodeconfigure, nous pouvons étendre le processus par défaut pour ignorer les nouveaux champs:

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Car car = objectMapper.readValue(jsonString, Car.class);

JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);
JsonNode jsonNodeYear = jsonNodeRoot.get("year");
String year = jsonNodeYear.asText();

Encore une autre option est basée sur leFAIL_ON_NULL_FOR_PRIMITIVES qui définit si les valeursnull pour les valeurs primitives sont autorisées:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);

De même,FAIL_ON_NUMBERS_FOR_ENUM contrôle si les valeurs d'énumération peuvent être sérialisées / désérialisées sous forme de nombres:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);

Vous pouvez trouver la liste complète des fonctionnalités de sérialisation et de désérialisation sur lesofficial site.

4.2. Création d'un sérialiseur ou d'un désérialiseur personnalisé

Une autre caractéristique essentielle de la classeObjectMapper est la possibilité d'enregistrer desserializer et desdeserializer personnalisés. Le sérialiseur et le désérialiseur personnalisés sont très utiles dans les situations où la réponse JSON d'entrée ou de sortie a une structure différente de celle de la classe Java dans laquelle elle doit être sérialisée ou désérialisée.

Voici un exemple de sérialiseur JSON personnalisé:

public class CustomCarSerializer extends StdSerializer {

    public CustomCarSerializer() {
        this(null);
    }

    public CustomCarSerializer(Class t) {
        super(t);
    }

    @Override
    public void serialize(
      Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("car_brand", car.getType());
        jsonGenerator.writeEndObject();
    }
}

Ce sérialiseur personnalisé peut être appelé comme ceci:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
  new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));
module.addSerializer(Car.class, new CustomCarSerializer());
mapper.registerModule(module);
Car car = new Car("yellow", "renault");
String carJson = mapper.writeValueAsString(car);

Voici à quoi ressemble leCar (en tant que sortie JSON) côté client:

var carJson = {"car_brand":"renault"}

Et voici un exemple dea custom JSON deserializer:

public class CustomCarDeserializer extends StdDeserializer {

    public CustomCarDeserializer() {
        this(null);
    }

    public CustomCarDeserializer(Class vc) {
        super(vc);
    }

    @Override
    public Car deserialize(JsonParser parser, DeserializationContext deserializer) {
        Car car = new Car();
        ObjectCodec codec = parser.getCodec();
        JsonNode node = codec.readTree(parser);

        // try catch block
        JsonNode colorNode = node.get("color");
        String color = colorNode.asText();
        car.setColor(color);
        return car;
    }
}

Ce désérialiseur personnalisé peut être appelé de la manière suivante:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
  new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Car.class, new CustomCarDeserializer());
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);

4.3. Gestion des formats de date

La sérialisation par défaut dejava.util.Date produit un nombre i.e. horodatage de la période (nombre de millisecondes depuis le 1er janvier 1970, UTC). Mais ceci n'est pas très lisible par l'homme et nécessite une conversion supplémentaire pour être affiché dans un format lisible par l'homme.

Encapsulons l'instanceCar que nous avons utilisée jusqu'à présent dans la classeRequest avec la propriétédatePurchased:

public class Request
{
    private Car car;
    private Date datePurchased;

    // standard getters setters
}

Pour contrôler le format de chaîne d’une date et définissez-le sur ex. yyyy-MM-dd HH:mm a z, considérez l'extrait de code suivant:

ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
objectMapper.setDateFormat(df);
String carAsString = objectMapper.writeValueAsString(request);
// output: {"car":{"color":"yellow","type":"renault"},"datePurchased":"2016-07-03 11:43 AM CEST"}

Pour en savoir plus sur la sérialisation des dates avec Jackson, lisezour more in-depth write-up.

4.4. Gestion des collections

Une autre fonctionnalité petite mais utile disponible via la classeDeserializationFeature est la possibilité de générer le type de collection que nous voulons à partir d'une réponse JSON Array.

Par exemple, nous pouvons générer le résultat sous forme de tableau:

String jsonCarArray =
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);
// print cars

Ou enList:

String jsonCarArray =
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
List listCar = objectMapper.readValue(jsonCarArray, new TypeReference>(){});
// print cars

Plus d'informations sur la gestion des collections avec Jackson sont disponibleshere.

5. Conclusion

Jackson est une bibliothèque de sérialisation / désérialisation JSON solide et mature pour Java. L'APIObjectMapper fournit un moyen simple d'analyser et de générer des objets de réponse JSON avec beaucoup de flexibilité.

L'article traite des principales caractéristiques qui rendent la bibliothèque si populaire. Le code source qui accompagne l'article se trouveover on GitHub.