您的位置:首页 > 其它

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

2016-09-26 15:17 363 查看

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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: