Als ich den JSON mit der Redmine REST-API erhielt, wurde die folgende Notation in "custom_fields" angezeigt.
"custom_fields": [
{
"id": 1,
"name": "Gegenstand 1",
"value": "a"
},
{
"id": 2,
"name": "Punkt 2",
"multiple": true,
"value": [
"b"
]
},
{
"id": 3,
"name": "Punkt 3",
"multiple": true,
"value": [
"c",
"d"
]
},
Es scheint, dass wenn der Inhalt von "Wert" "mehrfach": wahr "ist, es ein Array-Objekt ist, andernfalls ist es einzeln. Wie im obigen Beispiel gibt es 3 Muster.
Es gibt auch eine Methode, um alle in ein Array zu konvertieren, selbst wenn es zum Zeitpunkt der Deserialisierung einzeln ist (JSON → Java). Da es jedoch zum Zeitpunkt der Serialisierung nicht auf den ursprünglichen Ausdruck zurückgesetzt werden kann (ich weiß nicht, ob es sich um ein einzelnes Array oder ein Array mit 1 Element handelt), setzen Sie dieses Steuerelement In diesem Sinne habe ich auch eine allgemeine Implementierung in Betracht gezogen.
Die Objekte, die zum Zeitpunkt der Deserialisierung Daten speichern sollen, sind wie folgt.
public class MultipleType<T> {
private T value;
private List<T> values;
public boolean isMultiple() {
return values != null;
}
//Unter Getter/setter
}
Verwenden Sie entweder Wert oder Werte und machen Sie den anderen Null.
Die obigen "custom_fields" sehen wie folgt aus.
public class CustomField {
private String id;
private String name;
private boolean multiple;
private MultipleType<String> value;
//Unter Getter/setter
}
Ich möchte die Funktionen von GSON so oft wie möglich nutzen, daher werde ich den gleichen Feldnamen wie JSON verwenden.
Implementieren Sie den benutzerdefinierten Serializer / Deserializer von GSON wie folgt.
public class MultipleTypeAdapter implements JsonDeserializer<MultipleType<?>>, JsonSerializer<MultipleType<?>> {
@Override
public MultipleType<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
final MultipleType<?> result = new MultipleType<>();
if (json.isJsonArray()) {
result.setValues(deserializeArray(json, typeOfT, context));
} else {
result.setValue(context.deserialize(json, getGenericType(typeOfT)));
}
return result;
}
private <T> List<T> deserializeArray(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
final List<T> values = new ArrayList<>();
final Type t = getGenericType(typeOfT);
for (JsonElement e : json.getAsJsonArray()) {
values.add(context.deserialize(e, t));
}
return values;
}
/* get actual Type of <?> */
private Type getGenericType(Type typeOfT) {
return ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
}
@Override
public JsonElement serialize(MultipleType<?> src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src.isMultiple() ? src.getValues() : src.getValue());
}
}
Es gibt drei Hauptpunkte.
Besonders 2 ist etwas kompliziert. Zunächst müssen wir wissen, was das Argument "Type typeOfT" der Methode "deserialize" darstellt. Es enthält ein Objekt, das den Typparameter der JsonDeserializer-Schnittstelle darstellt. (Um genau zu sein, der Typ des Objekts, das zur Laufzeit tatsächlich verwendet wird) Generische Typparameter gehen zur Kompilierungszeit verloren, sodass Sie zur Laufzeit auf sie verweisen können.
Die Definition sagt uns, dass "typeOfT" "MultipleType >" Ist. Da wir jedoch den ">" - Teil kennen müssen, erhalten wir die internen Typparameter mit der Methode "getGenericType". Ich werde.
Der Grund, warum der Laufzeit-Typ des Typparameters "<?>" Erforderlich ist, besteht darin, dass die nachfolgende Deserialisierung der Funktion von GSON überlassen werden kann, wenn der richtige Typ durch die Methode "context.deserialize" angegeben wird. .. Insbesondere müssen Sie keine komplexe Strukturdeserialisierung von Hand schreiben, wenn die Felder des Datenobjekts vom nicht-primitiven Typ sind (einschließlich Zeichenfolge).
Die Verwendung von GSON ist wie folgt.
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MultipleType.class, new MultipleTypeAdapter());
final Gson gson = gsonBuilder.create();
Da die Klasse "MultipleTypeAdapter" kein generischer Typ ist, ist es ein Fehler, dass keine Warnung angezeigt wird. Aus diesem Grund haben wir "<?>" (Platzhalter) für die benutzerdefinierten Deserializer / Serializer-Typparameter verwendet. (Ich kann nicht erklären, warum Platzhalter in Ordnung sind ...)
Ich benutze den generischen Java-Typ als "generisch" in Sätzen und die Aussprache als "generisch". Ist es nicht schwierig, "Generika" zu sagen?
Recommended Posts