什么时候会用到这个?
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;
}
}