Serialisieren und Deserialisieren von Enums mit Jackson
1. Überblick
Dieses kurze Tutorial zeigt, wie SieJava Enums are serialized and deserialized with Jackson 2 steuern.
Um etwas tiefer zu graben undother cool things we can do Jackson 2 zu lernen, gehen Sie zuthe main Jackson tutorial.
2. Steuern der Enum-Darstellung
Definieren wir die folgende Aufzählung:
public enum Distance {
KILOMETER("km", 1000),
MILE("miles", 1609.34),
METER("meters", 1),
INCH("inches", 0.0254),
CENTIMETER("cm", 0.01),
MILLIMETER("mm", 0.001);
private String unit;
private final double meters;
private Distance(String unit, double meters) {
this.unit = unit;
this.meters = meters;
}
// standard getters and setters
}
3. Serialisierung von Enums in JSON
3.1. Standard-Enum-Darstellung
Standardmäßig repräsentiert Jackson Java Enums als einfache Zeichenfolge - zum Beispiel:
new ObjectMapper().writeValueAsString(Distance.MILE);
Wird darin enden, dass:
"MILE"
Was wir beim Marshalling dieserEnum to a JSON Object erhalten möchten, ist, etwas zu geben wie:
{"unit":"miles","meters":1609.34}
3.2. Aufzählung als JSON-Objekt
Ab Jackson 2.1.2 gibt es jetzt eine Konfigurationsoption, die diese Art der Darstellung verarbeiten kann. Dies kann über die Annotation@JsonFormatauf Klassenebene erfolgen:
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Distance { ... }
Dies führt zum gewünschten Ergebnis, wenn dieseenum fürDistance.MILE serialisiert werden:
{"unit":"miles","meters":1609.34}
3.3. Aufzählungen und@JsonValue
Eine weitere einfache Möglichkeit, die Marshalling-Ausgabe für eine Aufzählung zu steuern, ist die Verwendung der Annotation@JsonValueauf einem Getter:
public enum Distance {
...
@JsonValue
public String getMeters() {
return meters;
}
}
Was wir hier ausdrücken, ist, dassgetMeters() die tatsächliche Darstellung dieser Aufzählung ist. Das Ergebnis der Serialisierung ist also:
1609.34
3.4. Benutzerdefinierter Serializer für Enum
Vor Jackson 2.1.2 oder wenn für die Aufzählung noch weitere Anpassungen erforderlich sind, können wir eincustom Jackson serializer.verwenden. Zuerst müssen wir es definieren:
public class DistanceSerializer extends StdSerializer {
public DistanceSerializer() {
super(Distance.class);
}
public DistanceSerializer(Class t) {
super(t);
}
public void serialize(Distance distance, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeFieldName("name");
generator.writeString(distance.name());
generator.writeFieldName("unit");
generator.writeString(distance.getUnit());
generator.writeFieldName("meters");
generator.writeNumber(distance.getMeters());
generator.writeEndObject();
}
}
Wir werden nun den Serializer auf die Klasse anwenden, die serialisiert werden soll:
@JsonSerialize(using = DistanceSerializer.class)
public enum TypeEnum { ... }
Was in ... endet:
{"name":"MILE","unit":"miles","meters":1609.34}
4. JSON für Enum deserialisieren
Definieren wir zunächst eine KlasseCitymit einem MitgliedDistance:
public class City {
private Distance distance;
...
}
Als Nächstes werden die verschiedenen Möglichkeiten zum Deserialisieren einer JSON-Zeichenfolge in eine Aufzählung erläutert.
4.1. Standardverhalten
By default, Jackson will use the Enum name to deserialize from JSON.
Beispielsweise wird der JSON deserialisiert:
{"distance":"KILOMETER"}
Zu einemDistance.KILOMETER Objekt:
City city = new ObjectMapper().readValue(json, City.class);
assertEquals(Distance.KILOMETER, city.getDistance());
4.2. Verwenden von@JsonValue
Wir haben gelernt, wie Sie@JsonValue zum Serialisieren von Enums verwenden. Dieselbe Annotation können wir auch für die Deserialisierung verwenden. Dies ist möglich, weil Enum-Werte Konstanten sind.
Verwenden wir zunächst@JsonValue mit einer der Getter-Methoden -getMeters():
public enum Distance {
...
@JsonValue
public double getMeters() {
return meters;
}
}
Der Rückgabewert der MethodegetMeters()repräsentiert nun die Enum-Objekte. Wenn Sie den Beispiel-JSON deserialisieren, geschieht Folgendes:
{"distance":"0.0254"}
Jackson sucht nach dem Enum-Objekt mit einemgetMeters()-Rückgabewert von 0,0254. In diesem Fall lautet das ObjektDistance.INCH:
assertEquals(Distance.INCH, city.getDistance());
4.3. Verwenden von@JsonProperty
Die Annotation@JsonPropertywird für Aufzählungsinstanzen verwendet:
public enum Distance {
@JsonProperty("distance-in-km")
KILOMETER("km", 1000),
@JsonProperty("distance-in-miles")
MILE("miles", 1609.34);
...
}
Mit dieser Annotation könnenwe are simply telling Jackson to map the value of the @JsonProperty to the object annotated with this value.
Aufgrund der obigen Deklaration lautet die JSON-Beispielzeichenfolge:
{"distance": "distance-in-km"}
Wird dem ObjektDistance.KILOMETERzugeordnet:
assertEquals(Distance.KILOMETER, city.getDistance());
4.4. Verwenden von@JsonCreator
Jackson ruft mit@JsonCreator annotierte Methoden auf, um eine Instanz der einschließenden Klasse abzurufen.
Betrachten Sie die JSON-Darstellung:
{
"distance": {
"unit":"miles",
"meters":1609.34
}
}
Definieren wir nun die Factory-Methode vonforValues()mit der Annotation von@JsonCreator:
public enum Distance {
@JsonCreator
public static Distance forValues(@JsonProperty("unit") String unit,
@JsonProperty("meters") double meters) {
for (Distance distance : Distance.values()) {
if (distance.unit.equals(unit) && Double.compare(distance.meters, meters) == 0) {
return distance;
}
}
return null;
}
...
}
Beachten Sie die Verwendung der Annotation@JsonProperty, um die JSON-Felder mit den Methodenargumenten zu binden.
Wenn wir dann das JSON-Beispiel deserialisieren, erhalten wir das Ergebnis:
assertEquals(Distance.MILE, city.getDistance());
4.5. Verwenden eines benutzerdefiniertenDeserializer
Ein benutzerdefinierter Deserializer kann verwendet werden, wenn keine der beschriebenen Techniken verfügbar ist. Beispielsweise haben wir möglicherweise keinen Zugriff auf den Enum-Quellcode oder verwenden eine ältere Jackson-Version, die eine oder mehrere der bisher behandelten Anmerkungen nicht unterstützt.
Gemäßour custom deserialization article erstellen wir zunächst die Deserialisierungsklasse, um den im vorherigen Abschnitt bereitgestellten JSON zu deserialisieren:
public class CustomEnumDeserializer extends StdDeserializer {
@Override
public Distance deserialize(JsonParser jsonParser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String unit = node.get("unit").asText();
double meters = node.get("meters").asDouble();
for (Distance distance : Distance.values()) {
if (distance.getUnit().equals(unit) && Double.compare(distance.getMeters(), meters) == 0) {
return distance;
}
}
return null;
}
}
Als Nächstes verwenden wir die Annotation@JsonDeserializein der Aufzählung, um unseren benutzerdefinierten Deserializer anzugeben:
@JsonDeserialize(using = CustomEnumDeserializer.class)
public enum Distance {
...
}
Und unser Ergebnis ist:
assertEquals(Distance.MILE, city.getDistance());
5. Fazit
Dieser Artikel zeigt, wie Sieserialization and deserialization processes and formats of Java Enums besser kontrollieren können.
Die Implementierung all dieser Beispiele und Codefragmente finden Sie inover on Github.