Gson学习-4

原文地址: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 以及JsonSerializerJsonDeserializer 都需要与 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

JsonSerializerJsonDeserializer 不用像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支持TypeAdapterTypeAdapterFactory( 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();

你可能感兴趣的:(Gson学习-4)