2012-01-14 2 views
34

Я читаю ответ JSON с Gson, который возвращает Somtimes NumberFormatException, поскольку ожидаемый int значение устанавливается равным пустой строке. Теперь мне интересно, как лучше всего справиться с таким исключением. Если значение является пустой строкой, то десериализации должен быть 0.Как обрабатывать NumberFormatException с Gson в десериализации JSON ответ

Ожидаемый ответ 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 возвращается пустая строка.

Есть ли способ сказать Gson «если вы десериализации поле runtime от типа Foo и есть NumberFormatException, просто возвращает значение по умолчанию 0»?

Моим обходным путем является использование String в качестве типа поля runtime вместо int, но, возможно, существует лучший способ обработки таких ошибок.

+0

Это точно не отвечает на ваш вопрос, но, может быть, вам следует просто опустить все поле «runtime» из JSON? –

+0

Также, что происходит, когда вы меняете поле из int в Integer? –

+0

JSON - это ответ веб-сервиса, который я не могу контролировать, но меня интересует среда выполнения. Изменение поля на Integer не имеет значения. – Soundlink

ответ

14

Сначала я попытался написать общий блок пользовательского типа для целых значений, чтобы поймать 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); 
+19

Вау, это много кода для чего-то, что должно быть тривиально: -s – Somatik

+3

Начиная с версии 2.3.1, GSON теперь позволяет вам регистрировать адаптеры типов для примитивных типов. Я смог решить ту же проблему, зарегистрировав 'JsonDeserializer' для' Integer.class', который возвращает 0 в случае 'NumberFormatException'. – Edward

2

Это может помочь вам всегда принимать значение по умолчанию 0 для поля runtime в случае исключения NumberFormatException, поскольку оно может быть единственным источником ошибок.

+0

Просьба пояснить, как вы могли бы сообщить об этом объекту Gson. – Soundlink

+0

Вы используете это с помощью адаптера типа. См. [Здесь] (http://grepcode.com/file/repository.jboss.org/maven2/org.jbpm.jbpm3/gwt-console/1.0.0.Beta2/com/google/gson/JsonDeserializer.java#JsonDeserializer) и [здесь] (http://grepcode.com/file/repository.jboss.org/maven2/org.jbpm.jbpm3/gwt-console/1.0.0.Beta2/com/google/gson/DefaultTypeAdapters.java) , –

+0

Конечно, более исправить решение будет искать недопустимый ввод в строке JSON с использованием regex и заменять его значением по умолчанию '0'. Но я бы рекомендовал против этого сильно. –

20

Вот пример, который я сделал для длинных type.This лучше вариант:

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); 
    } 
} 

Вы можете обратиться this link больше.

+0

Как зарегистрировать этот адаптер на gson builder? – masterdany88

+1

Gson gson = new GsonBuilder(). RegisterTypeAdapter (Long.class, новый LongTypeAdapter()). Create(); –

+0

Блестящий !! Cheers – CaptRisky

5

Я сделал это 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); 
    } 
} 

}

6

Быстрый и простой обходной путь - Просто измените свой член тип поля выполнения для строки и доступ к нему через геттер которая возвращает время выполнения как 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

необходимых
Смежные вопросы