我们摄入的API返回一些格式错误的JSON (特别是Double.NaN被序列化为带有“NaN”的String )。为了允许这个gson,gson总是将lenient设置为true,并正确地将其序列化回Double.NaN。
现在,我们希望使用RuntimeTypeAdapterFactory类从gson中删除一些样板代码。刚才描述的行为不再适用于这里,我们得到了信息
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 ExceptionRuntimeTypeAdapterFactory**:**中的实现
在检查来自RuntimeTypeAdapterFactory的代码时,我注意到lenient选项从未设置为true,因为我们调用了com.google.gson.TypeAdapter的fromJsonTree方法,在该方法中,我们创建了一个新的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和object被正确反序列化)。
现在的问题是:关于为什么我们不能在这里使用lenient选项,我缺少什么东西吗?乍一看,这似乎是来自gson的一个bug,但我不确定。
发布于 2020-01-16 00:05:52
由于gson-extras类来自核心库,所以它并不完全是一个bug。我建议再注册一个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();另请参阅:
https://stackoverflow.com/questions/59756092
复制相似问题