Einführung in den Jackson ObjectMapper

1. Übersicht

Dieses Tutorial konzentriert sich auf das Verständnis der Jackson ObjectMapper- Klasse und darauf, wie Java-Objekte in JSON serialisiert und JSON-Zeichenfolgen in Java-Objekte deserialisiert werden.

Um mehr über die Jackson-Bibliothek im Allgemeinen zu erfahren, ist das Jackson-Tutorial ein guter Anfang.

2. Abhängigkeiten

Fügen wir zunächst der pom.xml die folgenden Abhängigkeiten hinzu :

 com.fasterxml.jackson.core jackson-databind 2.11.1  

Diese Abhängigkeit fügt dem Klassenpfad auch transitiv die folgenden Bibliotheken hinzu:

  1. Jackson-Anmerkungen
  2. Jackson-Core

Verwenden Sie immer die neuesten Versionen aus dem zentralen Maven-Repository für Jackson-Databind .

3. Lesen und Schreiben mit ObjectMapper

Beginnen wir mit den grundlegenden Lese- und Schreibvorgängen.

Die einfache Readvalue API des ObjectMapper ist ein guter Einstiegspunkt. Wir können es verwenden, um JSON-Inhalte in ein Java-Objekt zu analysieren oder zu deserialisieren.

Auf der Schreibseite können wir auch die writeValue- API verwenden, um jedes Java-Objekt als JSON-Ausgabe zu serialisieren.

In diesem Artikel wird die folgende Fahrzeugklasse mit zwei Feldern als Objekt zum Serialisieren oder Deserialisieren verwendet:

public class Car { private String color; private String type; // standard getters setters }

3.1. Java-Objekt zu JSON

Mal sehen , ein Java - Objekt in JSON mit dem ein erstes Beispiel für die Serialisierung Writevalue Methode der ObjectMapper Klasse:

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

Die Ausgabe der obigen Angaben in der Datei lautet:

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

Die Methoden writeValueAsString und writeValueAsBytes von ObjectMapper Klasse eine JSON von einem Java - Objekt erzeugen und die erzeugte JSON als Zeichenfolge oder als ein Byte - Array zurück:

String carAsString = objectMapper.writeValueAsString(car); 

3.2. JSON zu Java-Objekt

Im Folgenden finden Sie ein einfaches Beispiel für die Konvertierung eines JSON-Strings in ein Java-Objekt mithilfe der ObjectMapper- Klasse:

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

Die Funktion readValue () akzeptiert auch andere Eingabeformen, z. B. eine Datei mit einer JSON-Zeichenfolge:

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

oder eine URL:

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

3.3. JSON an Jackson JsonNode

Alternativ kann ein JSON in ein JsonNode- Objekt analysiert und zum Abrufen von Daten von einem bestimmten Knoten verwendet werden:

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

3.4. Erstellen einer Java-Liste aus einer JSON-Array-Zeichenfolge

Wir können einen JSON in Form eines Arrays mithilfe einer TypeReference in eine Java-Objektliste analysieren :

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

3.5. Erstellen einer Java-Karte aus einer JSON-Zeichenfolge

Ebenso können wir einen JSON in eine Java Map analysieren :

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

4. Erweiterte Funktionen

Eine der größten Stärken der Jackson-Bibliothek ist der hochgradig anpassbare Serialisierungs- und Deserialisierungsprozess.

In diesem Abschnitt werden einige erweiterte Funktionen beschrieben, bei denen sich die Eingabe- oder Ausgabe-JSON-Antwort von dem Objekt unterscheiden kann, das die Antwort generiert oder verwendet.

4.1. Konfigurieren der Serialisierungs- oder Deserialisierungsfunktion

Wenn beim Konvertieren von JSON-Objekten in Java-Klassen die JSON-Zeichenfolge einige neue Felder enthält, führt der Standardprozess zu einer Ausnahme:

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

The JSON string in the above example in the default parsing process to the Java object for the Class Car will result in the UnrecognizedPropertyException exception.

Through the configure method, we can extend the default process to ignore the new fields:

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

Yet another option is based on the FAIL_ON_NULL_FOR_PRIMITIVES, which defines if the null values for primitive values are allowed:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false); 

Similarly, FAIL_ON_NUMBERS_FOR_ENUM controls if enum values are allowed to be serialized/deserialized as numbers:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);

You can find the comprehensive list of serialization and deserialization features on the official site.

4.2. Creating Custom Serializer or Deserializer

Another essential feature of the ObjectMapper class is the ability to register a custom serializer and deserializer.

Custom serializers and deserializers are very useful in situations where the input or the output JSON response is different in structure than the Java class into which it must be serialized or deserialized.

Below is an example of a custom JSON serializer:

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

This custom serializer can be invoked like this:

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

Here's what the Car looks like (as JSON output) on the client side:

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

And here's an example of a 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; } } 

This custom deserializer can be invoked in this way:

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. Handling Date Formats

The default serialization of java.util.Date produces a number, i.e., epoch timestamp (number of milliseconds since January 1, 1970, UTC). But this is not very human readable and requires further conversion to be displayed in a human-readable format.

Let's wrap the Car instance we used so far inside the Request class with the datePurchased property:

public class Request { private Car car; private Date datePurchased; // standard getters setters } 

To control the String format of a date and set it to, e.g., yyyy-MM-dd HH:mm a z, consider the following snippet:

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"} 

To learn more about serializing dates with Jackson, read our more in-depth write-up.

4.4. Handling Collections

Eine weitere kleine, aber nützliche Funktion, die über die DeserializationFeature- Klasse verfügbar ist, ist die Möglichkeit, den gewünschten Sammlungstyp aus einer JSON-Array-Antwort zu generieren.

Zum Beispiel können wir das Ergebnis als Array generieren:

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

Oder als Liste :

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

Weitere Informationen zum Umgang mit Sammlungen mit Jackson finden Sie hier.

5. Schlussfolgerung

Jackson ist eine solide und ausgereifte JSON-Serialisierungs- / Deserialisierungsbibliothek für Java. Die ObjectMapper- API bietet eine einfache Möglichkeit, JSON-Antwortobjekte mit viel Flexibilität zu analysieren und zu generieren. In diesem Artikel wurden die Hauptfunktionen erläutert, die die Bibliothek so beliebt machen.

Der dem Artikel beiliegende Quellcode ist auf GitHub zu finden.