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.