我知道你说过你已经尝试过了,但是使用 Boolean 字段应该可以。我把你的例子缩小了一点,它按预期工作。
我这样定义Settings 类:
public static class Settings {
@SerializedName("ad_native_enabled")
public Boolean nativeAdEnabled;
}
如果您随后解析包含该字段的 JSON:
String json = "{\"ad_native_enabled\": false}";
Settings settings = gson.fromJson(json, Settings.class);
System.out.println(settings.nativeAdEnabled); // prints false
而如果您解析不包含该字段的 JSON:
String emptyJson = "{}";
Settings emptySettings = gson.fromJson(emptyJson, Settings.class);
System.out.println(emptySettings.nativeAdEnabled); // prints null
您是否将字段的默认值保留为false?如果是这样,第二个示例也将打印false。此外,似乎 GSON 并不特别喜欢 JSON 对象中最后一个属性之后的尾随逗号 - 也许这就是您收到错误的原因?
看到您的评论后,我想了更多关于是否有可能以某种方式支持默认值,同时仍然能够判断该字段是否存在于 JSON 中。我能想出的最佳解决方案是引入一个新的包装器类型,带有一个自定义的反序列化器。
我首先定义了这个包装器类型,它只包含字段的实际值,以及该值是否为默认值的指示符:
public static class ValueWrapper<T> {
public final T value;
public final boolean isDefaultValue;
public ValueWrapper(T value, boolean isDefaultValue) {
this.value = value;
this.isDefaultValue = isDefaultValue;
}
}
Settings 类如下所示:
public static class Settings {
@SerializedName("ad_native_enabled")
public ValueWrapper<Boolean> nativeAdEnabled = new ValueWrapper<>(false, true);
}
在这里,我将字段定义为默认值为false,这就是为什么isDefaultValue 设置为true。
然后我为这种类型定义了一个自定义反序列化器。基本思路是取你试图反序列化的ValueWrapper的类型,提取其泛型参数,将JSON中的实际值反序列化为泛型参数类型,然后返回一个新的ValueWrapper,其中设置了isDefaultValue到false。这个反序列化器看起来像这样:
public static class ValueWrapperDeserializer implements JsonDeserializer<ValueWrapper<?>> {
@Override
public ValueWrapper<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
ParameterizedType parameterizedType = (ParameterizedType) typeOfT;
Type valueType = parameterizedType.getActualTypeArguments()[0];
Object value = context.deserialize(json, valueType);
return new ValueWrapper<>(value, false);
}
}
现在我们需要做的就是注册自定义反序列化器:
Gson gson = new GsonBuilder()
.registerTypeAdapter(ValueWrapper.class, new ValueWrapperDeserializer())
.create();
然后我们可以从上面运行我的两个示例:
String json = "{\"ad_native_enabled\": false}";
Settings settings = gson.fromJson(json, Settings.class);
System.out.println(settings.nativeAdEnabled.value); // prints false
System.out.println(settings.nativeAdEnabled.isDefaultValue); // prints false
String emptyJson = "{}";
Settings emptySettings = gson.fromJson(emptyJson, Settings.class);
System.out.println(emptySettings.nativeAdEnabled.value); // prints false
System.out.println(emptySettings.nativeAdEnabled.isDefaultValue); //prints true
所以这允许我们使用默认值,但仍然能够使用isDefaultValue 判断该字段是否已设置。这显然对Settings 对象的用户的API 产生了相当大的影响,但也许这比处理空值并将默认值存储在别处更简洁。