Как обрабатывать NumberFormatException с Gson при десериализации JSON-ответ
Я читаю ответ JSON с Gson, который возвращает somtimes a NumberFormatException
, потому что установлено ожидаемое значение int
к пустой строке. Теперь мне интересно, какой лучший способ справиться с этим видом исключения. Если значение представляет собой пустую строку, десериализация должна быть 0.
Ожидаемый ответ JSON:
{
"name" : "Test1",
"runtime" : 90
}
Но иногда среда выполнения представляет собой пустую строку:
{
"name" : "Test2",
"runtime" : ""
}
Класс java выглядит следующим образом:
public class Foo
{
private String name;
private int runtime;
}
И десериализация такова:
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
Gson gson = new Gson();
Foo foo = gson.fromJson(input, Foo.class);
Что выбрал com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
, потому что вместо значения int возвращается пустой String.
Есть ли способ рассказать Gson: "Если вы десериализуете поле runtime
для типа Foo
и существует исключение NumberFormatException, просто верните значение по умолчанию 0"?
Моим обходным решением является использование String
в качестве типа поля runtime
вместо int
, но, возможно, есть лучший способ справиться с такими ошибками.
Ответы
Ответ 1
Сначала я попытался написать общий адаптер настраиваемого типа для значений Integer, чтобы поймать NumberFormatException
и вернуть 0, но Gson не разрешает TypeAdaptors для примитивных типов:
java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer
После этого я ввел новый тип FooRuntime
для поля runtime
, поэтому класс Foo
теперь выглядит следующим образом:
public class Foo
{
private String name;
private FooRuntime runtime;
public int getRuntime()
{
return runtime.getValue();
}
}
public class FooRuntime
{
private int value;
public FooRuntime(int runtime)
{
this.value = runtime;
}
public int getValue()
{
return value;
}
}
Адаптер типа обрабатывает процесс десериализации:
public class FooRuntimeTypeAdapter implements JsonDeserializer<FooRuntime>, JsonSerializer<FooRuntime>
{
public FooRuntime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
int runtime;
try
{
runtime = json.getAsInt();
}
catch (NumberFormatException e)
{
runtime = 0;
}
return new FooRuntime(runtime);
}
public JsonElement serialize(FooRuntime src, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(src.getValue());
}
}
Теперь необходимо использовать GsonBuilder
для регистрации адаптера типа, поэтому пустая строка интерпретируется как 0 вместо того, чтобы бросать NumberFormatException
.
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(FooRuntime.class, new FooRuntimeTypeAdapter());
Gson gson = builder.create();
Foo foo = gson.fromJson(input, Foo.class);
Ответ 2
Вот пример, который я сделал для длинного типа. Это лучший вариант:
public class LongTypeAdapter extends TypeAdapter<Long>{
@Override
public Long read(JsonReader reader) throws IOException {
if(reader.peek() == JsonToken.NULL){
reader.nextNull();
return null;
}
String stringValue = reader.nextString();
try{
Long value = Long.valueOf(stringValue);
return value;
}catch(NumberFormatException e){
return null;
}
}
@Override
public void write(JsonWriter writer, Long value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(value);
}
}
Вы можете отправить эту ссылку для более подробной информации.
Ответ 3
Быстрое и простое обходное решение. Просто измените поле типа члена среды выполнения на String и получите доступ к нему через getter, который возвращает runtime как int:
public class Foo
{
private String name;
private String runtime;
public int getRuntime(){
if(runtime == null || runtime.equals("")){
return 0;
}
return Integer.valueOf(trackId);
}
}
= > нет необходимости десериализации json
Ответ 4
Я создал этот TypeAdapter, который проверяет наличие пустых строк и возвращает 0
public class IntegerTypeAdapter extends TypeAdapter<Number> {
@Override
public void write(JsonWriter jsonWriter, Number number) throws IOException {
if (number == null) {
jsonWriter.nullValue();
return;
}
jsonWriter.value(number);
}
@Override
public Number read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
}
try {
String value = jsonReader.nextString();
if ("".equals(value)) {
return 0;
}
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
}
Ответ 5
Это может помочь вам всегда принимать значение по умолчанию 0
для поля runtime
в случае исключения NumberFormatException, поскольку оно может быть единственным источником ошибок.