Câu hỏi Làm thế nào để xử lý một NumberFormatException với Gson trong deserialization một phản ứng JSON


Tôi đang đọc phản hồi JSON với Gson, trả về một lúc NumberFormatException vì dự kiến int giá trị được đặt thành một chuỗi trố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, quá trình deserialization phải là 0.

Phản hồi JSON mong đợi:

{
   "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 như thế này:

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

Và deserialization này 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 bởi vì một chuỗi rỗng được trả về thay vì một giá trị int.

Có cách nào nói với Gson không, "nếu bạn deserialize các lĩnh vực runtime Loại Foo và có một NumberFormatException, chỉ trả về giá trị mặc định 0"?

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


39
2018-01-14 16:09


gốc


Điều này không chính xác trả lời 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? - Mike Baranczak
Ngoài ra, điều gì sẽ xảy ra khi bạn thay đổi trường từ int thành Integer? - Mike Baranczak
JSON là phản hồi của một 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


Các câu trả lời:


Đây là ví dụ tôi đã làm cho loại Long.Đây 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 liên kết này để biết thêm.


23
2017-10-29 06:02



Làm cách nào để đăng ký bộ điều hợp này trên trình tạo gson? - masterdany88
Gson gson = new GsonBuilder (). RegisterTypeAdapter (Long.class, mới LongTypeAdapter ()). Create (); - Adrian B.
Rực rỡ!! Chúc mừng - CaptRisky
Liên kết dường như đã chết - Neon Warge


Lúc đầu, tôi đã cố gắng viết một bộ điều hợp kiểu 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 kiểu 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 runtime trường, vì vậy Foo lớp 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;
    }
}

Bộ điều hợp kiểu xử lý quá trình deserialization tùy chỉnh:

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ờ nó là cần thiết để sử dụng GsonBuilder để đăng ký bộ điều hợp kiểu, vì vậy một chuỗi rỗng được hiểu 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);

14
2018-01-14 23:59



wow, đó là rất nhiều mã cho một cái gì đó mà nên được tầm thường: -s - Somatik
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 cùng một vấn đề bằng cách đăng ký JsonDeserializer cho Integer.class trả về 0 trong trường hợp NumberFormatException. - Edward


Giải pháp nhanh chóng và dễ dàng - Chỉ cần thay đổi trường loại thành viên của bạn thành thời gian chạy thành String và truy cập nó thông qua getter trả về thời gian chạy dưới dạng 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 cần phải khai thác


8
2017-07-22 10:04



điều này là hoàn toàn lừa gạt bro - Michael


Tôi đã tạo TypeAdapter này để kiểm tra các 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);
    }
}

}


5
2017-07-24 23:45





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


2
2018-01-14 19:43



Vui lòng giải thích cách bạn sẽ nói với đối tượng Gson để làm điều đó. - Soundlink
Bạn làm điều đó bằng cách sử dụng một loại adapter. Xem đây và đây. - Milad Naseri
Tất nhiên, một giải pháp khắc phục và cố gắng hơn là tìm kiếm đầu vào không hợp lệ trong chuỗi JSON bằng cách sử dụng regex và thay thế bằng một giá trị mặc định 0 giá trị. Nhưng tôi khuyên bạn nên chống lại điều đó một cách mạnh mẽ. - Milad Naseri
Cảm ơn, nhận xét của bộ điều hợp loại đã cho tôi một số ý tưởng. - Soundlink
Không vấn đề gì. :) - Milad Naseri