原文地址:https://www.jianshu.com/p/e740196225a4
主要内容
1.TypeAdapter
2.JsonSerializer与JsonDeserializer
3.TypeAdapterFactory
4.@JsonAdapter注解
一、TypeAdapter
TypeAdapter
是一个抽象类,用于接管某种类型的序列化和反序列化过程,包含两个主要方法 write(JsonWriter,T)
和 read(JsonReader)
其它的方法都是final方法并最终调用这两个抽象方法
public abstract class TypeAdapter {
public abstract void write(JsonWriter out, T value) throws IOException;
public abstract T read(JsonReader in) throws IOException;
//其它final 方法就不贴出来了,包括`toJson`、`toJsonTree`、`toJson`和`nullSafe`方法。
}
整一个例子
自定义一个UserTypeAdapter
来接管User
的序列化和反序列化
//Extends可以理解为全盘继承了父类的功能。implements可以理解为为这个类附加一些额外的功能;
// interface定义一些方法,并没有实现,需要implements来实现才可用。
// implements一般是实现接口。extends 是继承类。
public class UserTypeAdapter extends TypeAdapter {
@Override
public void write(JsonWriter jsonWriter, User user) throws IOException {
jsonWriter.beginObject();
jsonWriter.name("name").value(user.name);
jsonWriter.name("age").value(user.age);
jsonWriter.name("email_Address").value(user.email);
jsonWriter.endObject();
}
@Override
public User read(JsonReader jsonReader) throws IOException {
User user = new User();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
switch (jsonReader.nextName()) {
case "name":
user.name = jsonReader.nextString();
break;
case "age":
user.age = jsonReader.nextInt();
break;
case "email":
case "email_address":
case "emailAddress":
case "email_Address":
user.email = jsonReader.nextString();
break;
}
}
jsonReader.endObject();
return user;
}
}
使用示例
注意:TypeAdapter
以及JsonSerializer
和 JsonDeserializer
都需要与 GsonBuilder.registerTypeAdapter
(配置Gson以进行自定义序列化或反序列化)或GsonBuilder.registerTypeHierarchyAdapter
配合使用,下面将不再重复说明。
String str = "{\"name\":\"星星\",\"age\":22,\"email\":\"[email protected]\"}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(User.class,new UserTypeAdapter())
.create();
User user = gson.fromJson(str,User.class);
System.out.println(user.toString());//User{name='星星', age=22, email='[email protected]'}
gson.toJson(user,System.out);//{"name":"星星","age":22,"email_Address":"[email protected]"}
二、JsonSerializer与JsonDeserializer
JsonSerializer
和JsonDeserialize
r 不用像TypeAdapter
一样,必须要实现序列化和反序列化的过程,你可以据需要选择,如只接管序列化的过程就用 JsonSerializer
,只接管反序列化的过程就用 JsonDeserializer
前面Gson学习-1介绍过反序列化例子JsonDeserializer
序列化例子
写一个负责转换的类,里面写好规则
public class Date2LongSerialize implements JsonSerializer {
@Override
public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
}
}
定义类
public class Model {
public String name;
//在需要转换的类型上加上注解
@JsonAdapter(Date2LongSerialize.class)
private Date date;
public Model() {
}
public Model(String name, Date date) {
this.name = name;
this.date = date;
}
@Override
public String toString() {
return "Model{" +
"name='" + name + '\'' +
", date=" + date +
'}';
}
}
使用
Model m = new Model("星星",new Date());
Gson gson = new Gson();
gson.toJson(m,System.out);//{"name":"星星","date":"2019-09-19 12:48:47"}
泛型
如果一个被序列化的对象本身就带有泛型,且注册了相应的TypeAdapter
,那么必须调用Gson.toJson(Object,Type)
,明确告诉Gson
对象的类型;否则,将跳过此注册的TypeAdapter
。
public static void main(String[] args) {
Type type = new TypeToken>() {}.getType();//被序列化的对象带有【泛型】List
TypeAdapter> typeAdapter = new TypeAdapter>() {
@Override
public void write(JsonWriter jsonWriter, List users) throws IOException {
// 省略
}
@Override
public List read(JsonReader jsonReader) throws IOException {
List res = new ArrayList<>();
jsonReader.beginArray();//数组开始
while (jsonReader.hasNext()) {
res.add(readUser(jsonReader));
}
jsonReader.endArray();//数组结束
return res;
}
// 函数读取单个User
public User readUser(JsonReader jsonReader) throws IOException {
User user = new User();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
switch (jsonReader.nextName()) {
case "name":
user.name = jsonReader.nextString();
break;
case "age":
user.age = jsonReader.nextInt();
break;
case "email":
case "email_address":
case "emailAddress":
case "email_Address":
user.email = jsonReader.nextString();
break;
}
}
jsonReader.endObject();
return user;
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(type, typeAdapter)//注册了与此type相应的TypeAdapter
.create();
List list = new ArrayList<>();
list.add(new User("a",11,"[email protected]"));
list.add(new User("b",22,"[email protected]"));
System.out.println(list);
String result = gson.toJson(list, type);//明确指定type时才会使用注册的TypeAdapter托管序列化和反序列化
System.out.println(result);
//[User{name='a', age=11, email='[email protected]'}, User{name='b', age=22, email='[email protected]'}]
String result2 = gson.toJson(list);//不指定type时使用系统默认的机制进行序列化和反序列化
System.out.println(result2);
//[{"name":"a","age":11,"email":"[email protected]"},{"name":"b","age":22,"email":"[email protected]"}]
}
三、TypeAdapterFactory
解释:用于生产TypeAdapter的工厂类。
通过对比Type
,确定有没有对应的TypeAdapter
,没有就返回null
,与GsonBuilder.registerTypeAdapterFactory
配合使用。
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public TypeAdapter create(Gson gson, TypeToken type) {
if (type.getType() == Integer.class || type.getType() == int.class)
return intTypeAdapter;//这个单独写
return null;
}
})
.create();
四、@JsonAdapter注解
上面已经有使用的痕迹了
其实主要使用在类上面
@JsonAdapter(UserTypeAdapter.class) //加在类上
public class User {
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String name;
public int age;
@SerializedName(value = "emailAddress")
public String email;
}
使用时不用再使用GsonBuilder
去注册UserTypeAdapter
了。
注:@JsonAdapter
支持TypeAdapter
或TypeAdapterFactory
( 2.7开始已经支持 JsonSerializer/JsonDeserializer
)
问题:
服务器返回的数据中data字段类型不固定,比如请求成功data是一个List,不成功的时候是String类型,这样前端在使用泛型解析的时候,怎么去处理呢?
正确的数据返回姿势:同一个接口任何情况下不得改变返回类型,要么就不要返,要么就返空值,如null、[],{}
。
解决方案
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(List.class, new JsonDeserializer>() {
@Override
public List> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
//是list数组
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();