Optioneel gebruiken met Jackson

1. Inleiding

In dit artikel geven we een overzicht van de Optioneel class, en leg dan enkele problemen uit die we kunnen tegenkomen als we het met Jackson gebruiken.

Hierna zullen we een oplossing introduceren die Jackson zal behandelen Optioneel alsof het gewone nulbare objecten zijn.

2. Probleemoverzicht

Laten we eerst eens kijken wat er gebeurt als we proberen te serialiseren en deserialiseren Optioneel met Jackson.

2.1. Afhankelijkheid van Maven

Laten we ervoor zorgen dat we de nieuwste versie gebruiken om Jackson te gebruiken:

 com.fasterxml.jackson.core jackson-core 2.11.1 

2.2. Ons boekobject

Laten we vervolgens een klas maken Boek, met een gewone en een Optioneel veld:

public class Book {String title; Optionele ondertitel; // getters en setters weggelaten}

Houd daar rekening mee Optioneel mogen niet als velden worden gebruikt en we doen dit om het probleem te illustreren.

2.3. Serialisatie

Laten we nu een instantiëren Boek:

Boek boek = nieuw boek (); book.setTitle ("Oliver Twist"); book.setSubTitle (Optioneel.of ("The Parish Boy's Progress"));

En tot slot, laten we proberen het te serialiseren met een Jackson ObjectMapper:

String resultaat = mapper.writeValueAsString (boek);

We zullen zien dat de uitvoer van de Optioneel field, bevat niet zijn waarde, maar in plaats daarvan een genest JSON-object met een veld genaamd Cadeau:

{"title": "Oliver Twist", "subTitle": {"present": true}}

Hoewel dit er misschien vreemd uitziet, is het eigenlijk wat we zouden moeten verwachten.

In dit geval, is aanwezig() is een openbare vangst op de Optioneel klasse. Dit betekent dat het wordt geserialiseerd met een waarde van waar of false, afhankelijk van of het leeg is of niet. Dit is Jackson's standaard serialisatiegedrag.

Als we erover nadenken, willen we de werkelijke waarde van de ondertitel veld dat moet worden geserialiseerd.

2.4. Deserialisatie

Laten we nu ons vorige voorbeeld omkeren, deze keer proberen we een object te deserialiseren in een Optioneel. We zullen zien dat we nu een JsonMappingException:

@Test (verwacht = JsonMappingException.class) public void givenFieldWithValue_whenDeserializing_thenThrowException String bookJson = "{\" title \ ": \" Oliver Twist \ ", \" subTitle \ ": \" foo \ "}"; Boekresultaat = mapper.readValue (bookJson, Book.class); } 

Laten we de stacktracering bekijken:

com.fasterxml.jackson.databind.JsonMappingException: kan geen instantie van java.util construeren.Optional: geen String-argument constructor / fabrieksmethode om te deserialiseren vanuit String-waarde ('The Parish Boy's Progress')

Dit gedrag is weer logisch. In wezen heeft Jackson een constructor nodig die de waarde van ondertitel als argument. Dit is niet het geval bij onze Optioneel veld.

3. Oplossing

Wat we willen, is dat Jackson een lege behandelt Optioneel net zo nul, en om een ​​cadeau te behandelen Optioneel als een veld dat de waarde ervan vertegenwoordigt.

Gelukkig is dit probleem voor ons opgelost. Jackson heeft een set modules die omgaan met JDK 8-datatypes, inclusief Optioneel.

3.1. Afhankelijkheid en registratie van Maven

Laten we eerst de nieuwste versie toevoegen als een Maven-afhankelijkheid:

 com.fasterxml.jackson.datatype jackson-datatype-jdk8 2.9.6 

Nu hoeven we alleen nog maar de module te registreren bij onze ObjectMapper:

ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.registerModule (nieuwe Jdk8Module ());

3.2. Serialisatie

Laten we het nu testen. Als we proberen onze Boek object opnieuw, we zullen zien dat er nu een ondertitel, in tegenstelling tot een geneste JSON:

Boek boek = nieuw boek (); book.setTitle ("Oliver Twist"); book.setSubTitle (Optioneel.of ("The Parish Boy's Progress")); String serializedBook = mapper.writeValueAsString (boek); assertThat (van (serializedBook) .getString ("subTitle")) .isEqualTo ("The Parish Boy's Progress");

Als we proberen een leeg boek te serialiseren, wordt het opgeslagen als nul:

book.setSubTitle (Optioneel.empty ()); String serializedBook = mapper.writeValueAsString (boek); assertThat (van (serializedBook) .getString ("subTitle")). isNull ();

3.3. Deserialisatie

Laten we nu onze tests voor deserialisatie herhalen. Als we ons boek herlezen, zullen we zien dat we niet langer een JsonMappingException:

Boek newBook ​​= mapper.readValue (resultaat, Book.class); assertThat (newBook.getSubTitle ()). isEqualTo (Optioneel.of ("The Parish Boy's Progress"));

Laten we tot slot de test opnieuw herhalen, deze keer met nul. We zullen zien dat we nog maar eens geen JsonMappingException, en in feite, heb een lege Optioneel:

assertThat (newBook.getSubTitle ()). isEqualTo (Optioneel.empty ());

4. Conclusie

We hebben laten zien hoe u dit probleem kunt omzeilen door gebruik te maken van de JDK 8 DataTypes-module, waarmee we laten zien hoe Jackson hiermee een lege Optioneel net zo nul, en een cadeautje Optioneel als een gewoon veld.

De implementatie van deze voorbeelden is te vinden op GitHub; dit is een op Maven gebaseerd project, dus het zou gemakkelijk moeten zijn zoals het is.