Handling of the exception of empty string parsing by Gson

In the face of some nonstandard json, our gson parsing often throws a variety of exceptions that cause the app to crash. Here are some measures to avoid this

I tried some solutions to the array type field parsing exception, but there are problems in the end. If you have a good solution, I hope you can post it below. Thank you very much Exception example = > normal json:

{
    "code":0,
    "msg":"ok",
    "data":[    //Contract to array
      {
        "id":5638,
        "newsId":5638
      }
      ]
}

Exception json:

{
    "code":0,
    "msg":"ok",
    "data":{}    //Return as object or empty string
}

Abnormal situation of Json

Let's first look at a json returned by the background
Normally, json:

{
    "code":0,
    "msg":"ok",
    "data":{
        "id":5638,
        "newsId":5638
    }
}

Entity class corresponding to data part:

public class JsonBean {
    private int id;
    private int newsId;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getNewsId() {
        return newsId;
    }

    public void setNewsId(int newsId) {
        this.newsId = newsId;
    }
}

Exception JSON (no corresponding data is found in the background database newsId field):

{
    "code":0,
    "msg":"ok",
    "data":{
        "id":5638,
        "newsId":""
    }
}

In this way, Gson will throw an exception of parsing error when parsing, and app will crash because it is unable to convert '' to int

json exception handling

We expect that when the json exception returned in the background is resolved successfully, the null value corresponding to the conversion to the default value, such as: newsId=0;
It's still up to you to correct the output of the backstage developers---

To write a type converter for int value, we need to implement the jsonserializer < T > interface and jsondeserializer < T > interface of Gson, that is, the serialization and deserialization interface

public class IntegerDefault0Adapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
    @Override
    public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        try {
            if (json.getAsString().equals("") || json.getAsString().equals("null")) {//Defined as int type, 0 if the background returns' 'or null
                return 0;
            }
        } catch (Exception ignore) {
        }
        try {
            return json.getAsInt();
        } catch (NumberFormatException e) {
            throw new JsonSyntaxException(e);
        }
    }

    @Override
    public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src);
    }
}

Same as Long and Double type

double=>

public class DoubleDefault0Adapter implements JsonSerializer<Double>, JsonDeserializer<Double> {
    @Override
    public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        try {
            if (json.getAsString().equals("") || json.getAsString().equals("null")) {//Defined as double type, if the background returns "" or null, it returns 0.00
                return 0.00;
        }
            } catch (Exception ignore) {
        }
        try {
            return json.getAsDouble();
        } catch (NumberFormatException e) {
            throw new JsonSyntaxException(e);
        }
    }

    @Override
    public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src);
    }
}

long=>

public class LongDefault0Adapter implements JsonSerializer<Long>, JsonDeserializer<Long> {
    @Override
    public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
        try {
            if (json.getAsString().equals("") || json.getAsString().equals("null")) {//Defined as long type, 0 if the background returns' 'or null
                    return 0l;
                }
            } catch (Exception ignore) {
        }
        try {
            return json.getAsLong();
        } catch (NumberFormatException e) {
            throw new JsonSyntaxException(e);
        }
    }

    @Override
    public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src);
    }
}

So the usage is as follows:

return new Retrofit.Builder()
       .client(okHttpClient)//Set up network access framework
       .addConverterFactory(GsonConverterFactory.create(buildGson()))//Add json transformation framework
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//Let Retrofit support RxJava
       .baseUrl(baseUrl)
       .build();

/**
 * "Increase background return" "and" "null" "processing"
 * 1.int=>0
 * 2.double=>0.00
 * 3.long=>0L
 *
 * @return
 */
public static Gson buildGson() {
    if (gson == null) {
        gson = new GsonBuilder()
                .registerTypeAdapter(Integer.class, new IntegerDefault0Adapter())
                .registerTypeAdapter(int.class, new IntegerDefault0Adapter())
                .registerTypeAdapter(Double.class, new DoubleDefault0Adapter())
                .registerTypeAdapter(double.class, new DoubleDefault0Adapter())
                .registerTypeAdapter(Long.class, new LongDefault0Adapter())
                .registerTypeAdapter(long.class, new LongDefault0Adapter())
                .create();
    }
    return gson;
}

No more crashes because the background json field is empty

Tags: JSON Retrofit Database network

Posted on Thu, 30 Apr 2020 04:36:26 -0400 by kporter.porter