Introduktion till Jackson ObjectMapper

1. Översikt

Denna handledning fokuserar på att förstå Jackson ObjectMapper- klassen och hur man serialiserar Java-objekt till JSON och deserialiserar JSON-sträng till Java-objekt.

För att förstå mer om Jackson-biblioteket i allmänhet är Jackson Tutorial ett bra ställe att börja.

2. Beroenden

Låt oss först lägga till följande beroenden i pom.xml :

 com.fasterxml.jackson.core jackson-databind 2.11.1  

Detta beroende kommer också att lägga till följande bibliotek i klassvägen:

  1. jackson-anteckningar
  2. jackson-core

Använd alltid de senaste versionerna från Maven central repository för jackson-databind .

3. Läsa och skriva med ObjectMapper

Låt oss börja med de grundläggande läs- och skrivoperationerna.

Den enkla readValue API av ObjectMapper är en bra startpunkt. Vi kan använda den för att analysera eller deserialisera JSON-innehåll till ett Java-objekt.

skrivsidan kan vi också använda writeValue API för att serieera alla Java-objekt som JSON-utdata.

Vi använder följande bilklass med två fält som objekt för att serie- eller deserialisera genom hela den här artikeln:

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

3.1. Java-objekt till JSON

Låt oss se ett första exempel på att serieera ett Java-objekt till JSON med hjälp av writeValue- metoden i ObjectMapper- klassen:

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

Resultatet av ovanstående i filen kommer att vara:

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

Metoderna writeValueAsString och writeValueAsBytes av ObjectMapper- klassen genererar en JSON från ett Java-objekt och returnerar den genererade JSON som en sträng eller som en byte-array:

String carAsString = objectMapper.writeValueAsString(car); 

3.2. JSON till Java-objekt

Nedan följer ett enkelt exempel på att konvertera en JSON-sträng till ett Java-objekt med ObjectMapper- klassen:

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

Den readValue () funktionen accepterar även andra former av indata, såsom en fil som innehåller JSON-sträng:

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

eller en URL:

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

3.3. JSON till Jackson JsonNode

Alternativt kan en JSON analyseras i ett JsonNode- objekt och användas för att hämta data från en specifik nod:

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

3.4. Skapa en Java-lista från en JSON Array-sträng

Vi kan analysera en JSON i form av en matris i en Java-objektlista med hjälp av en TypeReference :

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

3.5. Skapa Java-karta från JSON-sträng

På samma sätt kan vi analysera en JSON på en Java- karta :

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

4. Avancerade funktioner

En av Jacksonbibliotekets största styrkor är den mycket anpassningsbara serie- och deserialiseringsprocessen.

I det här avsnittet går vi igenom några avancerade funktioner där ingången eller utgången JSON-svar kan skilja sig från objektet som genererar eller förbrukar svaret.

4.1. Konfigurera funktionen Serialization eller Deserialization

Vid konvertering av JSON-objekt till Java-klasser, om JSON-strängen har några nya fält, kommer standardprocessen att leda till ett undantag:

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

JSON-strängen i exemplet ovan i standardparsningsprocessen till Java-objektet för klassbilen resulterar i undantaget UnrecognizedPropertyException .

Genom konfigurationsmetoden kan vi utöka standardprocessen så att de ignorerar de nya fälten :

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

Ännu ett alternativ är baserat på FAIL_ON_NULL_FOR_PRIMITIVES , som definierar om nullvärdena för primitiva värden är tillåtna:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false); 

På samma sätt styr FAIL_ON_NUMBERS_FOR_ENUM om enumvärden får serieras / deserialiseras som nummer:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);

Du hittar den omfattande listan över funktioner för serialisering och deserialisering på den officiella webbplatsen.

4.2. Skapa anpassad Serializer eller 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

En annan liten men användbar funktion som är tillgänglig genom DeserializationFeature- klassen är möjligheten att generera den typ av samling vi vill ha från ett JSON Array-svar.

Till exempel kan vi generera resultatet som en matris:

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

Eller som en lista :

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

Mer information om hantering av samlingar med Jackson finns här.

5. Sammanfattning

Jackson är ett solidt och moget JSON-serialiserings- / deserialiseringsbibliotek för Java. Den ObjectMapper API ger ett enkelt sätt att tolka och generera JSON svarsobjekt med en stor flexibilitet. Den här artikeln diskuterade de viktigaste funktionerna som gör biblioteket så populärt.

Källkoden som följer med artikeln finns på GitHub.