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

来源:互联网 发布:java acos函数 编辑:程序博客网 时间:2024/05/26 15:56

Gson自定义适配器

学习github项目中遇到了特殊的解析出错的问题,查了好久,最后是需要自定义适配器,以前没用过这东西:(以下内容只是方便自己记忆,不做其他用途)参考:http://www.jianshu.com/p/3108f1e44155


目录

  • Gson自定义适配器
    • 目录
    • 什么时候会用到这个
    • TypeAdapter
    • JsonSerializer与JsonDeserializer
    • registerTypeAdapter与registerTypeHierarchyAdapter
    • 自己解决的问题使用retrofit解析网络访问以下是回调处理MatchPlayerInfo字段本该返回对象却返回空字符串引起的问题腾讯NBA的Json的坑

什么时候会用到这个?

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;    }}
0 0
原创粉丝点击