API, который мы принимаем, возвращает некоторое искаженное JSON (в частности, Double.NaN
сериализуется в String
с "NaN"). Чтобы разрешить этому gson всегда устанавливать lenient
в true и правильно сериализовать его обратно в Double.NaN
.
Теперь мы хотели использовать класс RuntimeTypeAdapterFactory
из gson-extras для удаления некоторый шаблонный код. Только что описанное поведение здесь больше не применяется, мы получаем сообщение
java .lang.NumberFormatException: JSON запрещает NaN и бесконечности: NaN
, что должен был быть проигнорирован из-за опции lenient
, обычно устанавливаемой из gson.
Рассмотрим небольшой пример:
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, потому что мы вызываем fromJsonTree
метод com.google.gson.TypeAdapter
, в котором мы создаем новый 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
и объект получить s десериализовано правильно с указанным типом).
Теперь вопрос: есть ли что-то, чего мне не хватает, почему мы не можем использовать опцию lenient
здесь? На первый взгляд это ошибка от gson-extras , но я не уверен.