How to handle a NumberFormatException with Gson in deserialization a JSON response

后端 未结 7 616
情深已故
情深已故 2020-12-01 03:45

I\'m reading a JSON response with Gson, which returns somtimes a NumberFormatException because an expected int value is set to an empty string. Now

相关标签:
7条回答
  • 2020-12-01 03:55

    At first, I tried to write a general custom type adaptor for Integer values, to catch the NumberFormatException and return 0, but Gson doesn't allow TypeAdaptors for primitive Types:

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

    After that I introduced a new Type FooRuntime for the runtime field, so the Foo class now looks like this:

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

    A type adaptor handles the custom deserialization process:

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

    Now it's necessary to use GsonBuilder to register the type adapter, so an empty string is interpreted as 0 instead of throwing a 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);
    
    0 讨论(0)
  • 2020-12-01 04:03

    Here is example I did for Long type.This is better option:

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

    Register the adapter upon creation of the gson util:

    Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new LongTypeAdapter()).create();
    

    You can refer to this link for more.

    0 讨论(0)
  • 2020-12-01 04:05

    Quick and easy workaround - Just change your member type field of runtime to String and access it via getter that returns runtime as an int:

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

    => no json deserialization neccessary

    0 讨论(0)
  • 2020-12-01 04:05

    This solution works for Double types. This will only work for non-primitive types:

    public class DoubleGsonTypeAdapter implements JsonDeserializer<Double> {
    
        @Override
        public Double deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            Double result = null;
            try {
                result = jsonElement.getAsDouble();
            } catch (NumberFormatException e) {
                return result;
            }
            return result;
        }
    }
    

    Model:

    @SerializedName("rateOfInterest")
    public Double rateOfInterest;
    @SerializedName("repaymentTenure")
    public Double repaymentTenure;
    @SerializedName("emiAmount")
    public Double emiAmount;
    

    Retrofit client:

    Gson gson = new GsonBuilder().registerTypeAdapter(Double.class, new DoubleGsonTypeAdapter()) .create();
    
    Retrofit retrofit = new Retrofit.Builder()
                    .client(okHttpClient)
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();
    
    0 讨论(0)
  • 2020-12-01 04:07

    I've made this TypeAdapter which check for empty strings and return 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);
        }
    }
    

    }

    0 讨论(0)
  • 2020-12-01 04:15

    It might help you to always assume a default value of 0 for the field runtime in case of a NumberFormatException, since it can be the only source of error.

    0 讨论(0)
提交回复
热议问题