Dies ist eine großartige Frage, da sie etwas isoliert, das einfach sein sollte, aber tatsächlich viel Code erfordert.
Schreiben Sie zunächst eine Zusammenfassung TypeAdapterFactory
, die Ihnen Hooks zum Ändern der ausgehenden Daten gibt. In diesem Beispiel wird eine neue API in Gson 2.2 verwendet getDelegateAdapter()
, mit der Sie den Adapter nachschlagen können, den Gson standardmäßig verwenden würde. Die Delegatenadapter sind äußerst praktisch, wenn Sie nur das Standardverhalten optimieren möchten. Und im Gegensatz zu vollständigen benutzerdefinierten Adaptern bleiben diese beim Hinzufügen und Entfernen von Feldern automatisch auf dem neuesten Stand.
public abstract class CustomizedTypeAdapterFactory<C>
implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
@SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
@Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
@Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {@code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {@code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
Die obige Klasse verwendet die Standardserialisierung, um einen JSON-Baum (dargestellt durch JsonElement
) abzurufen , und ruft dann die Hook-Methode beforeWrite()
auf, damit die Unterklasse diesen Baum anpassen kann. Ähnliches gilt für die Deserialisierung mit afterRead()
.
Als nächstes unterteilen wir dies für das spezifische MyClass
Beispiel. Zur Veranschaulichung füge ich der Karte eine synthetische Eigenschaft namens "Größe" hinzu, wenn sie serialisiert wird. Und aus Symmetriegründen werde ich es entfernen, wenn es deserialisiert ist. In der Praxis kann dies eine beliebige Anpassung sein.
private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
private MyClassTypeAdapterFactory() {
super(MyClass.class);
}
@Override protected void beforeWrite(MyClass source, JsonElement toSerialize) {
JsonObject custom = toSerialize.getAsJsonObject().get("custom").getAsJsonObject();
custom.add("size", new JsonPrimitive(custom.entrySet().size()));
}
@Override protected void afterRead(JsonElement deserialized) {
JsonObject custom = deserialized.getAsJsonObject().get("custom").getAsJsonObject();
custom.remove("size");
}
}
Fügen Sie zum Schluss alles zusammen, indem Sie eine angepasste Gson
Instanz erstellen , die den neuen Typadapter verwendet:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();
Die neuen Typen TypeAdapter und TypeAdapterFactory von Gson sind äußerst leistungsfähig, aber auch abstrakt und erfordern eine effektive Anwendung. Hoffentlich finden Sie dieses Beispiel hilfreich!
new MyClassTypeAdapterFactory()
mit dem privaten Ctor instanziieren ...Es gibt einen anderen Ansatz. Wie Jesse Wilson sagt, soll das einfach sein. Und raten Sie mal, es ist einfach!
Wenn Sie
JsonSerializer
undJsonDeserializer
für Ihren Typ implementieren , können Sie die gewünschten Teile verarbeiten und für alles andere mit sehr wenig Code an Gson delegieren . Ich zitiere der Einfachheit halber aus der Antwort von @ Perception auf eine andere Frage. Weitere Informationen finden Sie in dieser Antwort:Ich werde jedoch anerkennen, dass Jesses Ansatz besser aussieht, wenn Sie häufig Felder in Ihrem Java-Objekt ändern. Es ist ein Kompromiss zwischen Benutzerfreundlichkeit und Flexibilität. Treffen Sie Ihre Wahl.
quelle
value
gsonMein Kollege erwähnte auch die Verwendung der
@JsonAdapter
Anmerkunghttps://google.github.io/gson/apidocs/com/google/gson/annotations/JsonAdapter.htmlDie Seite wurde hierher verschoben: https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/JsonAdapter.html
Beispiel:
quelle