Gson自定义适配器处理特殊解析异常

什么时候会用到这个?

1、本来解析字符串 “24” 转成int 的24,但如果有些情况下给你返了个空字符串,实际上我们需要把空字符串转成一个固定的值-1 
2、本来是解析一个对象,但是后台直接传回来一个null(这表示整个对象是null,正常一般后台会new一个空对象给你) 
3、服务器返回的数据中data字段类型不固定,比如请求成功data是一个List,不成功的时候是String类型,这样前端在使用泛型解析的时候

TypeAdapter

Gson2.0开始提供的抽象类,两个主要的方法

    public abstract class TypeAdapter<T> {
        public abstract void write(JsonWriter out, T value) throws IOException;
        public abstract T read(JsonReader in) throws IOException;
    }

一般与GsonBuilder.registerTypeAdapter 示或GsonBuilder.registerTypeHierarchyAdapter配合使用

使用实例:

User user = new User("张三", 20);
user.idnum = "342401199108165674";
Gson gson = new GsonBuilder()
        //为User注册TypeAdapter
        .registerTypeAdapter(User.class, new UserTypeAdapter())
        .create();
System.out.println(gson.toJson(user));

public class UserTypeAdapter extends TypeAdapter<User> {

    @Override
    public void write(JsonWriter out, User value) throws IOException {
        out.beginObject();
        out.name("name").value(value.name);
        out.name("age").value(value.age);
        out.name("idnum").value(value.idnumm);
        out.endObject();
    }

    @Override
    public User read(JsonReader in) throws IOException {
        User user = new User();
        in.beginObject();
        while (in.hasNext()) {
            switch (in.nextName()) {
                case "name":
                    user.name = in.nextString();
                    break;
                case "age":
                    user.age = in.nextInt();
                    break;
                case "idnum":
                    user.idnum = in.nextString();
                    break;
            }
        }
        in.endObject();
        return user;
    }
}

注意:用过自定义适配器之后,注解就失效了比如:@SerializedName

针对问题一:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Integer.class, new TypeAdapter<Integer>() {
            @Override
            public void write(JsonWriter out, Integer value) throws IOException {
                out.value(String.valueOf(value)); 
            }
            @Override
            public Integer read(JsonReader in) throws IOException {
                try {
                    return Integer.parseInt(in.nextString());
                } catch (NumberFormatException e) {
                    return -1;
                }
            }
        })
        .create();

JsonSerializer与JsonDeserializer

JsonSerializer(序列化,其实就是toJson)与JsonDeserializer(反序列化,其实就是转化为对象),把TypeAdapter的功能细化

序列化:

JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {
    @Override
    public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(String.valueOf(src));
    }
};
Gson gson = new GsonBuilder()
        .registerTypeAdapter(Integer.class, numberJsonSerializer)

反序列化:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Integer.class, new JsonDeserializer<Integer>() {
            @Override
            public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                try {
                    return json.getAsInt();
                } catch (NumberFormatException e) {
                    return -1;
                }
            }
        })
        .create();

registerTypeAdapter与registerTypeHierarchyAdapter

registerTypeAdapter支持泛型,registerTypeHierarchyAdapter支持继承 
泛型:

Type type = new TypeToken<List<User>>() {}.getType();
TypeAdapter typeAdapter = new TypeAdapter<List<User>>() {
   //略
};
Gson gson = new GsonBuilder()
        .registerTypeAdapter(type, typeAdapter)
        .create();
List<User> list = new ArrayList<>();
list.add(new User("a",11));
list.add(new User("b",22));

继承:

JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {
    @Override
    public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(String.valueOf(src));
    }
};
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Number.class, numberJsonSerializer)
        .create();

解决问题三: 
方法一:

Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(List.class, new JsonDeserializer<List<?>>() {
    @Override
    public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonArray()){
            //这里要自己负责解析了
            Gson newGson = new Gson();
            return newGson.fromJson(json,typeOfT);
        }else {
            //和接口类型不符,返回空List
            return Collections.EMPTY_LIST;
        }
    }
}).create();

方法二:(效率高)

 Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(List.class, new JsonDeserializer<List<?>>() {
    @Override
    public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonArray()) {
            JsonArray array = json.getAsJsonArray();
            //获取泛型的实际类型
            Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
            List list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JsonElement element = array.get(i);
                Object item = context.deserialize(element, itemType);
                list.add(item);
            }
            return list;
        } else {
            //和接口类型不符,返回空List
            return Collections.EMPTY_LIST;
        }
    }
}).create();

自己解决的问题(使用retrofit解析网络访问,以下是回调),处理MatchPlayerInfo字段本该返回对象,却返回空字符串引起的问题(腾讯NBA的Json的坑)

 Call<String> call = api.getMatchCalendar(teamId, year, month);
        call.enqueue(new retrofit2.Callback<String>() {
            @Override
            public void onResponse(Call<String> call, retrofit2.Response<String> response) {
                if (response != null && !TextUtils.isEmpty(response.body())) {
                    String jsonStr = response.body();
                    //主要在这
                    MatchCalendar match = JsonParser.parseWithGson(MatchCalendar.class, jsonStr);
                    cbk.onSuccess(match);
                    cache.put(key, match);
                    LogUtils.i("resp:" + jsonStr);
                } else {
                    cbk.onFailure("获取数据失败");
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                cbk.onFailure(t.getMessage());
            }
        });
public class JsonParser {

    static Gson gson = new GsonBuilder().serializeNulls()
         //自定义类型适配器
        .registerTypeAdapter(MatchPlayerInfo.class, new MatchPlayerInfoDefaultAdapter())
        .registerTypeHierarchyAdapter(List.class, new ListDefaultAdapter())
        .create();

    public static <T> T parseWithGson(Class<T> classOfT, String jsonStr) {
        return gson.fromJson(jsonStr, classOfT);
    }
}
public class MatchPlayerInfoDefaultAdapter implements JsonSerializer<MatchPlayerInfo>, JsonDeserializer<MatchPlayerInfo> {
    @Override
    public MatchPlayerInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        try {
            //处理空字符串
            if (json.getAsString().equals("")) {
                return null;
                //return new MatchPlayerInfo();
            }
        } catch (Exception ignore) {
        }
        try {
            return new Gson().fromJson(json, MatchPlayerInfo.class);
        } catch (NumberFormatException e) {
            throw new JsonSyntaxException(e);
        }
    }

    @Override
    public JsonElement serialize(MatchPlayerInfo src, Type typeOfSrc, JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();
        Class<?> clz = src.getClass();
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                jsonObject.addProperty(field.getName(), (String) field.get(src));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return jsonObject;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值