Gson自定义反序列化器未调用空值

时间:2016-02-07 23:25:50

标签: java gson deserialization

我在JavaFX上下文中使用Gson序列化。为了避免在我的序列化Json中使用属性样板文件,我创建了一些自定义序列化器/反序列化器来编写属性的值而不是实际的属性对象,特别是这个用于泛型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);
    }
}

在我偶然发现空值之前,它运作良好。按照设计,当属性的值为null(不是属性本身)时,我的序列化程序将写入null,因为它写入值而不是属性(我使用Gson.serializeNulls()来实际写入它)。

我的问题是,在反序列化时,我的自定义序列化程序未调用空值,因为com.google.gson.TreeTypeAdapter中的这些行导致了a Gson bug

@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);
}

反序列化后,此导致属性本身为空,而不是包含空值的非null属性。

他们将错误标记为已修复,因为显然有使用TypeAdapterFactory的解决方法,但我似乎无法弄清楚如何做到这一点。看起来我必须手动反序列化对象,但我不知道它的类型所以我不能。 TypeAdapter方法readwrite没有向我提供当前JsonDeserializationContext的{​​{1}},因此我不能依赖其标准反序列化我的价值(我使用自定义反序列化器很容易做到)。

Gson

有谁知道如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

对于未来的读者: 我不喜欢我在其他答案中首先实现的解决方案,因此我将其更改为使用TypeAdapter而不是自定义反序列化器。

这需要更多代码来编写,所以我最终编写了一个轻量级库,专门用于在JavaFX的上下文中使用Gson,因此没有人必须再次编写它:)

这是:FxGson

答案 1 :(得分:0)

对于那些有同样问题的人,我使用了一个简单的解决方法:只要属性的内容为null,我就将我的属性序列化为特定的字符串“null”。我考虑到反序列化,一切正常。

这是我的代码:

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
        }
    }
}

潜在问题

如果属性为Property<String>并且其值实际上为“null”(或者您选择占位符的任何内容),则此方法存在一个问题。

但是,这不应该是一个问题,因为人们应该使用StringProperty而不是Property<String>,无论如何都会使用自己的序列化程序。

您可以找到my full FxGson class on Github 编辑:当我创建FxGson with TypeAdapters

时,此类不再存在