我在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
方法read
和write
没有向我提供当前JsonDeserializationContext
的{{1}},因此我不能依赖其标准反序列化我的价值(我使用自定义反序列化器很容易做到)。
Gson
有谁知道如何解决这个问题?
答案 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 with TypeAdapters FxGson
class on Github。