Gson benutzerdefinierte deserializer nicht genannt, die für null-Werte

Ich bin mit der Gson-Serialisierung in eine JavaFX-Kontext. Um zu vermeiden, dass Eigentum boilerplate in meiner serialisierten Json, habe ich mir eine Handvoll custom serialisierungsprogramme/deserializers zu schreiben, die den Wert der Eigenschaft anstelle der eigentlichen property-Objekt, insbesondere für die generische Property<T>:

private static class PropertySerializer implements JsonSerializer<Property<?>> {
    @Override
    public JsonElement serialize(Property<?> property, Type type, JsonSerializationContext context) {
        Object value = property.getValue();
        return context.serialize(value);
    }
}

private static class PropertyDeserializer implements JsonDeserializer<Property<?>> {
    @Override
    public Property<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonNull()) {
            System.out.println("I am never printed");
        }
        Type typeParam = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
        Object obj = context.deserialize(json, typeParam);
        return new SimpleObjectProperty<>(obj);
    }
}

Es funktionierte ziemlich gut, bis ich stolperte über null-Werte. Durch design, wenn der Wert der Eigenschaft ist null (nicht die Eigenschaft selbst), meine serializer schreiben eine null, weil er schreibt der Wert, nicht die Eigenschaft (die ich verwendet habe Gson.serializeNulls() zu machen, die tatsächlich schreiben).

Mein problem ist, dass bei der Deserialisierung Zeit, meine benutzerdefinierte serializer ist nicht genannt, die für null-Werte, weil ein Gson-bug, die durch diese Linien in com.google.gson.TreeTypeAdapter:

@Override public T read(JsonReader in) throws IOException {
    if (deserializer == null) {
        return delegate().read(in);
    }
    JsonElement value = Streams.parse(in);
    if (value.isJsonNull()) {
        return null; //bypasses my custom deserializer! Why you do dat to me?
    }
    return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext);
}

Diese Ergebnisse in der Unterkunft selbst null nach der Deserialisierung statt einer nicht-null-Eigenschaft, die einen null-Wert.


Sie markiert den bug als behoben, denn anscheinend gibt es einen workaround mit einem TypeAdapterFactory, aber ich kann nicht scheinen, um herauszufinden, wie es zu tun. Es sieht aus wie ich manuell Deserialisieren das Objekt, aber ich weiß nicht seine Art, so kann ich nicht. Die TypeAdapter Methoden read und write nicht mich mit den JsonDeserializationContext meiner aktuellen Gson, so kann ich nicht verlassen sich auf Ihren standard-Deserialisierung für meinen Wert (die habe ich ganz einfach mit den custom-deserializer).

private static class PropertyTypeAdapter extends TypeAdapter<Property<?>> {

    @Override
    public void write(JsonWriter out, Property<?> value) throws IOException {
        Object valueToSerialize = value.getValue();
        //how to use standard serialization of my object?
    }

    @Override
    public Property<?> read(JsonReader in) throws IOException {
        switch (in.peek()) {
            case NULL:
                return new SimpleObjectProperty<>(null);
            default:
                Type typeOfT = ???
                Type typeParam = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
                return ???; //how to invoke standard deserialization of my object?
        }
    }
}

Weiß jemand, wie man dieses Problem lösen?

InformationsquelleAutor Joffrey | 2016-02-07



2 Replies
  1. 1

    Für zukünftige Leser:
    Ich wusste nicht, wie die Lösung implementiert habe ich zuerst in meiner anderen Antwort, also änderte ich es zu benutzen TypeAdapter anstelle von einem benutzerdefinierten deserializer.

    Dies nimmt mehr code zu schreiben, so landete ich schreiben ein leichtes Bibliothek, zugeschnitten auf die Verwendung Gson im Kontext von JavaFX, so dass niemand hat, es wieder zu schreiben 🙂

    Hier ist es: FxGson.

    • Hallo, mein TypeAdapter ist (von meinem TypeAdapterFactory) read-Methode nicht aufgerufen werden, für null-Werte. Und ich kann nicht finden, eine richtige Art und Weise zu zwingen, es zu Deserialisieren null-Werte. Wie haben Sie dieses Problem zu beheben?
    • in der Regel sind Sie gefordert, null-Werte, aber ich glaube nicht, Sie werden dann aufgerufen, wenn die Eigenschaft fehlt im json-Format. Haben Sie enabled „serializeNulls“ auf Ihrem Gson?
    • Soweit ich herausgefunden serializeNulls() nicht auf der Deserialisierung. Auch, weder custom deserializers, noch benutzerdefinierte TypeAdapters sind aufgerufen, bei der null-Felder. Quelle: ich gedebuggt viel die letzten zwei Tage; auch: siehe Kommentar hier – github.com/google/gson/issues/948
    • Sorry für unklar zu sein, ich war nur vorausgesetzt, Sie waren zu Deserialisieren Ihrer eigenen Serialisierung. Mein Punkt war eher, „versuchen Sie zu Deserialisieren, wird ein null-Wert oder ein Feld?“. That being said, was Sie gefunden haben ist sehr seltsam, weil die Gson Jungs tatsächlich sagte mir an der Zeit, ein TypeAdapter statt einer Deserializer vor allem weitergegeben werden null-Werte.
    • FYI dies ist, wo mir wurde gesagt, verwenden Sie eine TypeAdapter. Das Problem habe ich versucht zu beheben mit dem PR diese eine. Vielleicht ist Ihr problem liegt in Ihrer TypeAdapterFactory?
    • Ich denke, ich tatsächlich verwendet das Beispiel JakeWharton aus dem ersten thread verlinkt (der code ist fast das gleiche), aber read() – Methode wird nie aufgerufen, wenn der eigentliche JSON-Wert ist null. Wenn es einen anderen Wert, es funktioniert Prima, mein TypeAdapter-Methode aufgerufen wird.
    • Sorry für belästigen Sie mein team beschlossen, zu gehen die andere Weise zu behandeln dieses Problem. Vielleicht werde ich nach einer separaten und richtig formulierte Frage ALSO später, wenn ich freie Zeit haben. Vielen Dank für Ihre Hilfe!
    • Keine Sorge. Ich wäre daran interessiert zu wissen, Ihre endgültige Ansatz, wenn Sie Zeit haben. Viel Glück

  2. 0

    Für diejenigen, die das gleiche problem haben, habe ich eine einfache Lösung: ich serialisieren meine Immobilie zu einem bestimmten String „null“, wenn sich der Inhalt der Eigenschaft ist null. Ich nehme die Rechnung für die Deserialisierung und alles funktioniert einwandfrei.

    Hier ist mein code:

    private static class PropertySerializer implements JsonSerializer<Property<?>>, JsonDeserializer<Property<?>> {
    
        private static final String NULL_PLACEHOLDER = "null";
    
        @Override
        public JsonElement serialize(Property<?> property, Type type, JsonSerializationContext context) {
            Object value = property.getValue();
            return context.serialize(value != null ? value : NULL_PLACEHOLDER);
        }
    
        @Override
        public Property<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            if (isNullPlaceholder(json)) {
                return new SimpleObjectProperty<>(null);
            }
            Type typeParam = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
            Object obj = context.deserialize(json, typeParam);
            return new SimpleObjectProperty<>(obj);
        }
    
        private static boolean isNullPlaceholder(JsonElement json) {
            try {
                return json.isJsonPrimitive() && NULL_PLACEHOLDER.equals(json.getAsString());
            } catch (ClassCastException e) {
                return false; //not a string, so definitely not the placeholder
            }
        }
    }

    Mögliches Problem

    Es gibt ein problem mit diesem Ansatz, wenn die Eigenschaft eine Property<String> und seinen Wert „null“ (oder was auch immer Sie wählen als Platzhalter).

    Jedoch sollte dies nicht ein Problem sein, da sollten Menschen mit StringProperty statt Property<String>, die gehen über seine eigenen serializer sowieso.

    können Sie finden meine volle FxGson – Klasse auf Github.
    Edit: diese Klasse existiert nicht mehr, wie ich geschaffen FxGson mit TypeAdapters

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.