2012-01-14 32 views
34

Tôi đang đọc một phản ứng JSON với Gson, trả về somtimes một NumberFormatException vì giá trị mong đợi int được đặt thành một chuỗi rỗng. Bây giờ tôi tự hỏi cách tốt nhất để xử lý loại ngoại lệ này là gì. Nếu giá trị là một chuỗi rỗng, các deserialization nên 0.Làm thế nào để xử lý một NumberFormatException với Gson trong deserialization một phản ứng JSON

mong đợi phản ứng JSON:

{ 
    "name" : "Test1", 
    "runtime" : 90 
} 

Nhưng đôi khi thời gian chạy là một chuỗi rỗng:

{ 
    "name" : "Test2", 
    "runtime" : "" 
} 

Lớp java trông giống như này:

public class Foo 
{ 
    private String name; 
    private int runtime; 
} 

Và quá trình deserialization là:

String input = "{\n" + 
       " \"name\" : \"Test\",\n" + 
       " \"runtime\" : \"\"\n" + 
       "}"; 

Gson gson = new Gson(); 
Foo foo = gson.fromJson(input, Foo.class); 

Mà ném một com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String vì một chuỗi trống được trả về thay vì giá trị int.

Có cách nào để nói với Gson, "nếu bạn deserialize lĩnh vực này runtime của Type Foo và có một NumberFormatException, chỉ cần trả về giá trị mặc định 0"?

Giải pháp thay thế của tôi là sử dụng String làm Loại trường runtime thay vì int, nhưng có thể có cách tốt hơn để xử lý các lỗi như vậy.

+0

Điều này không trả lời chính xác câu hỏi của bạn, nhưng có lẽ bạn chỉ nên bỏ qua toàn bộ trường "thời gian chạy" từ JSON? –

+0

Ngoài ra, điều gì sẽ xảy ra khi bạn thay đổi trường từ int thành Integer? –

+0

JSON là phản hồi của dịch vụ web mà tôi không thể kiểm soát, nhưng tôi quan tâm đến thời gian chạy trường. Thay đổi trường thành Số nguyên không tạo ra sự khác biệt. – Soundlink

Trả lời

14

Lúc đầu, tôi đã cố gắng để viết một bộ chuyển đổi kiểu tùy chỉnh chung cho các giá trị Integer, để bắt NumberFormatException và trở về 0, nhưng Gson không cho phép TypeAdaptors cho các loại nguyên thủy:

java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer 

Sau đó tôi giới thiệu một loại mới FooRuntime cho trường runtime, vì vậy lớp Foo bây giờ trông như thế này:

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

một bộ chuyển đổi loại xử lý các quá trình tùy chỉnh deserialization:

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

Bây giờ là cần thiết để sử dụng GsonBuilder đăng ký adapter loại, vì vậy một chuỗi rỗng được hiểu như là 0 thay vì ném một 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

wow, đó là rất nhiều mã cho một cái gì đó cần được tầm thường: -s – Somatik

+3

Kể từ phiên bản 2.3.1, GSON hiện cho phép bạn đăng ký bộ điều hợp kiểu cho các kiểu nguyên thủy. Tôi đã có thể giải quyết vấn đề tương tự bằng cách đăng ký một 'JsonDeserializer' cho' Integer.class' trả về 0 trong trường hợp 'NumberFormatException'. – Edward

2

Nó có thể giúp bạn luôn luôn giả định một giá trị mặc định là 0 cho trường runtime trong trường hợp ngoại lệ NumberFormatException, vì nó có thể là nguồn duy nhất của lỗi.

+0

Vui lòng giải thích cách bạn sẽ báo cho đối tượng Gson thực hiện điều đó. – Soundlink

+0

Bạn thực hiện việc đó bằng bộ điều hợp loại. Xem [tại đây] (http://grepcode.com/file/repository.jboss.org/maven2/org.jbpm.jbpm3/gwt-console/1.0.0.Beta2/com/google/gson/JsonDeserializer.java#JsonDeserializer) và [tại đây] (http://grepcode.com/file/repository.jboss.org/maven2/org.jbpm.jbpm3/gwt-console/1.0.0.Beta2/com/google/gson/DefaultTypeAdapters.java) . –

+0

Tất nhiên, một giải pháp khắc phục và cố gắng hơn là tìm đầu vào không hợp lệ trong chuỗi JSON bằng regex và thay thế bằng giá trị '0' mặc định. Nhưng tôi khuyên bạn nên chống lại điều đó một cách mạnh mẽ. –

20

Dưới đây là ví dụ tôi đã làm cho Long type.This là lựa chọn tốt hơn:

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

Bạn có thể tham khảo this link để biết thêm.

+0

Cách đăng ký bộ điều hợp này trên trình tạo gson? – masterdany88

+1

Gson gson = new GsonBuilder(). RegisterTypeAdapter (Long.class, mới LongTypeAdapter()). Create(); –

+0

Brilliant !! Chúc mừng – CaptRisky

5

Tôi đã thực hiện TypeAdapter này mà kiểm tra chuỗi rỗng và trở về 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

workaround nhanh chóng và dễ dàng - Chỉ cần thay đổi kiểu trường thành viên của bạn trong thời gian chạy để String và truy cập nó qua getter trả về thời gian chạy như một int:

public class Foo 
{ 
    private String name; 
    private String runtime; 

    public int getRuntime(){ 
     if(runtime == null || runtime.equals("")){ 
      return 0; 
     } 
     return Integer.valueOf(trackId); 
    } 
} 

=> không json deserialization cần thiết

Các vấn đề liên quan