【问题标题】:Use Gson RuntimeTypeAdapterFactory with lenient = true setting将 Gson RuntimeTypeAdapterFactory 与 lenient = true 设置一起使用
【发布时间】:2020-01-15 16:50:21
【问题描述】:

我们提取的 API 返回一些格式错误的 JSON(特别是 Double.NaN 被序列化为带有“NaN”的 String)。 要允许此 gson 始终将 lenient 设置为 true 并将其正确序列化回 Double.NaN

现在,我们想使用 gson-extras 中的 RuntimeTypeAdapterFactory 类来删除一些样板代码。 刚才描述的行为在这里不再适用,我们得到消息

java.lang.NumberFormatException:JSON 禁止 NaN 和无穷大:NaN

哪个 由于通常从 gson 设置的 lenient 选项应该被忽略。

考虑这个小例子:

class Base
{
   String type;
   double malformedField;
}

class A extends Base{}
class B extends Base{}

我们使用type 字段来确定我们想要哪个子类,否则我们当然无法推断出正确的类型。

这是我们用来创建子类和反序列化的设置:

RuntimeTypeAdapterFactory<Base> adapterFactory = RuntimeTypeAdapterFactory.of(Base.class, "type", true)
    .registerSubtype(A.class, "A")
    .registerSubtype(B.class, "B");

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(adapterFactory)
    //.setLenient() // Has no effect at all
    .create();

String json = "{\"type\":\"A\", \"malformedField\": \"NaN\"}";
Base a = gson.fromJson(json, Base.class); // throws said Exception

RuntimeTypeAdapterFactory 中的实现:

在检查RuntimeTypeAdapterFactory 的代码时,我注意到lenient 选项从未设置为true,因为我们调用com.google.gson.TypeAdapterfromJsonTree 方法,其中我们创建了一个新的JsonTreeReader,没有可以更改 lenient 选项。

public final T fromJsonTree(JsonElement jsonTree) {
    try {
        JsonReader jsonReader = new JsonTreeReader(jsonTree);
        return read(jsonReader);
    } catch (IOException e) {
        throw new JsonIOException(e);
    }
}

我尝试通过调试手动将其设置为true,这似乎按预期工作(没有 NumberFormatException 并且对象被正确反序列化为指定类型)。

现在的问题是:为什么我们不能在这里使用lenient 选项,我是否遗漏了什么?乍一看,这似乎是 gson-extras 的错误,但我不确定。

【问题讨论】:

    标签: java json polymorphism gson deserialization


    【解决方案1】:

    这不是gson-extras 的错误,因为com.google.gson.TypeAdapter 类来自核心库。我建议再注册一个TypeAdapterFactory 并为所有JsonReader 实例强制lenient

    class AlwaysLenientTypeAdapterFactory implements TypeAdapterFactory {
    
        public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
            return createCustomTypeAdapter(delegate);
        }
    
        private <T> TypeAdapter<T> createCustomTypeAdapter(TypeAdapter<T> delegate) {
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    delegate.write(out, value);
                }
    
                @Override
                public T read(JsonReader in) throws IOException {
                    in.setLenient(true);
                    return delegate.read(in);
                }
            };
        }
    }
    

    用法:

    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(adapterFactory)
            .registerTypeAdapterFactory(new AlwaysLenientTypeAdapterFactory())
            .create();
    

    另见:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多