Hoe enums te serialiseren en deserialiseren met Jackson

1. Overzicht

Deze korte tutorial laat zien hoe je de weg kunt bepalen Java-enums worden geserialiseerd en gedeserialiseerd met Jackson 2.

Om een ​​beetje dieper te graven en te leren andere leuke dingen die we kunnen doen Jackson 2 - ga naar de belangrijkste Jackson-tutorial.

2. Beheren van de Enum-weergave

Laten we de volgende Enum definiëren:

openbare opsomming Afstand {KILOMETER ("km", 1000), MILE ("mijl", 1609,34), METER ("meter", 1), INCH ("inches", 0,0254), CENTIMETER ("cm", 0,01), MILLIMETER ("mm", 0,001); privé String-eenheid; privé laatste dubbele meters; privéafstand (String-eenheid, dubbele meters) {this.unit = unit; this.meters = meters; } // standaard getters en setters}

3. Enums serialiseren naar JSON

3.1. Standaard Enum-weergave

Jackson stelt standaard Java Enums voor als een eenvoudige tekenreeks, bijvoorbeeld:

nieuwe ObjectMapper (). writeValueAsString (Distance.MILE);

Zal resulteren in:

"MIJL"

Wat we zouden willen krijgen bij het rangschikken hiervan Enum naar een JSON-object is iets geven als:

{"unit": "miles", "meter": 1609.34} 

3.2. Enum als JSON-object

Beginnend met Jackson 2.1.2 is er nu een configuratie-optie die dit soort representaties aankan. Dit kan gedaan worden via de @JsonFormat annotatie op klasniveau:

@JsonFormat (shape = JsonFormat.Shape.OBJECT) openbare opsomming Afstand {...}

Dit zal leiden tot het gewenste resultaat bij het serialiseren hiervan opsomming voor Afstand.MIJL:

{"unit": "miles", "meter": 1609.34}

3.3. Enums en @JsonValue

Nog een andere eenvoudige manier om de marshaling-uitvoer voor een enum te besturen, is door de @JsonValue annotatie op een getter:

public enum Distance {... @JsonValue public String getMeters () {retourmeters; }}

Wat we hier uitdrukken, is dat getMeters () is de feitelijke weergave van deze opsomming. Het resultaat van serialisering is dus:

1609.34

3.4. Custom Serializer voor Enum

Vóór Jackson 2.1.2, of als er nog meer aanpassingen nodig zijn voor de enum, kunnen we een aangepaste Jackson-serialisator. Eerst moeten we het definiëren:

openbare klasse DistanceSerializer breidt StdSerializer uit {openbare DistanceSerializer () {super (Distance.class); } openbare DistanceSerializer (klasse t) {super (t); } public void serialize (afstandsafstand, JsonGenerator-generator, SerializerProvider-provider) gooit IOException, JsonProcessingException {generator.writeStartObject (); generator.writeFieldName ("naam"); generator.writeString (afstand.name ()); generator.writeFieldName ("eenheid"); generator.writeString (distance.getUnit ()); generator.writeFieldName ("meter"); generator.writeNumber (afstand.getMeters ()); generator.writeEndObject (); }}

We zullen nu de serialisator toepassen op de klasse die wordt geserialiseerd:

@JsonSerialize (using = DistanceSerializer.class) openbare opsomming TypeEnum {...}

Wat resulteert in:

{"name": "MILE", "unit": "miles", "meter": 1609.34}

4. Deserialiseren van JSON naar Enum

Laten we eerst een stad klasse met een Afstand lid:

openbare klasse Stad {privé Afstand afstand; ...}

Vervolgens bespreken we de verschillende manieren om een ​​JSON-string te deserialiseren naar een Enum.

4.1. Standaardgedrag

Jackson gebruikt standaard de Enum-naam om uit JSON te deserialiseren.

Het zal bijvoorbeeld de JSON deserialiseren:

{"distance": "KILOMETER"}

Naar een Afstand.KILOMETER voorwerp:

City city = new ObjectMapper (). ReadValue (json, City.class); assertEquals (Distance.KILOMETER, city.getDistance ());

4.2. Gebruik makend van @JsonValue

We hebben geleerd hoe we ze moeten gebruiken @JsonValue om Enums te serialiseren. We kunnen dezelfde annotatie ook gebruiken voor deserialisatie. Dit is mogelijk omdat Enum-waarden constanten zijn.

Laten we eerst gebruiken @JsonValue met een van de getter-methoden - getMeters ():

openbare opsomming Afstand {... @JsonValue openbare dubbele getMeters () {retourmeters; }}

Nu is de geretourneerde waarde van getMeters () methode vertegenwoordigt de Enum-objecten. Dus bij het deserialiseren van de voorbeeld-JSON:

{"distance": "0.0254"}

Jackson zoekt naar het Enum-object met een getMeters () retourwaarde van 0,0254. In dit geval is het object Afstand.INCH:

assertEquals (Distance.INCH, city.getDistance ()); 

4.3. Gebruik makend van @JsonProperty

De @JsonProperty annotatie wordt gebruikt bij opsommingsinstanties:

openbare opsomming Afstand {@JsonProperty ("afstand-in-km") KILOMETER ("km", 1000), @JsonProperty ("afstand-in-mijlen") MILE ("mijlen", 1609.34); ...}

Door deze annotatie te gebruiken, we vertellen Jackson gewoon dat hij de waarde van de @JsonProperty naar het object dat met deze waarde is geannoteerd.

Als resultaat van de bovenstaande verklaring, de voorbeeld JSON-string:

{"distance": "distance-in-km"}

Wordt toegewezen aan het Afstand.KILOMETER voorwerp:

assertEquals (Distance.KILOMETER, city.getDistance ());

4.4. Gebruik makend van @RTLnieuws

Jackson roept methoden aan die zijn geannoteerd met @RTLnieuws om een ​​instantie van de insluitende klasse op te halen.

Overweeg de JSON-weergave:

{"distance": {"unit": "miles", "meter": 1609.34}}

Laten we nu de forValues ​​() fabrieksmethode met de @RTLnieuws annotatie:

public enum Distance {@JsonCreator public static Distance forValues ​​(@JsonProperty ("unit") String unit, @JsonProperty ("meter") dubbele meters) {for (Distance distance: Distance.values ​​()) {if (distance.unit. is gelijk aan (eenheid) && Double.compare (afstand.meters, meter) == 0) {retourafstand; }} retourneer null; } ...}

Let op het gebruik van @JsonProperty annotatie om de JSON-velden te binden met de methode-argumenten.

Als we vervolgens het JSON-monster deserialiseren, krijgen we het resultaat:

assertEquals (Distance.MILE, city.getDistance ());

4.5. Met behulp van een Custom Deserializer

Een aangepaste deserialisator kan worden gebruikt als geen van de beschreven technieken beschikbaar is. We hebben bijvoorbeeld geen toegang tot de Enum-broncode, of we gebruiken een oudere Jackson-versie die een of meer van de annotaties die tot nu toe zijn behandeld niet ondersteunt.

Volgens ons aangepaste deserialisatie-artikel, om de JSON uit de vorige sectie te deserialiseren, beginnen we met het maken van de deserialisatieklasse:

openbare klasse CustomEnumDeserializer breidt StdDeserializer uit {@Override public Distance deserialize (JsonParser jsonParser, DeserializationContext ctxt) gooit IOException, JsonProcessingException {JsonNode node = jsonParser.getCodec (). readTree) (jsonParserree); String unit = node.get ("unit"). AsText (); dubbele meters = node.get ("meters"). asDouble (); for (Distance distance: Distance.values ​​()) {if (distance.getUnit (). equals (unit) && Double.compare (distance.getMeters (), meters) == 0) {retourafstand; }} retourneer null; }} 

Vervolgens gebruiken we de @JsonDeserialize annotatie op de Enum om onze aangepaste deserializer te specificeren:

@JsonDeserialize (using = CustomEnumDeserializer.class) openbare opsomming Afstand {...}

En ons resultaat is:

assertEquals (Distance.MILE, city.getDistance ());

5. Conclusie

Dit artikel illustreert hoe u meer controle kunt krijgen over serialisatie- en deserialisatieprocessen en formaten van Java Enums.

De implementatie van al deze voorbeelden en codefragmenten is te vinden op GitHub.