Gson学习-4

2019-09-19  本文已影响0人  盼旺

原文地址: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<T> {
    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<User> {
    @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\":\"5456s45@qq.com\"}";
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='5456s45@qq.com'}
gson.toJson(user,System.out);//{"name":"星星","age":22,"email_Address":"5456s45@qq.com"}

二、JsonSerializer与JsonDeserializer

JsonSerializerJsonDeserializer 不用像TypeAdapter一样,必须要实现序列化和反序列化的过程,你可以据需要选择,如只接管序列化的过程就用 JsonSerializer ,只接管反序列化的过程就用 JsonDeserializer
前面Gson学习-1介绍过反序列化例子JsonDeserializer
序列化例子
写一个负责转换的类,里面写好规则

public class Date2LongSerialize implements JsonSerializer<Date> {
    @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<List<User>>() {}.getType();//被序列化的对象带有【泛型】List<T>
        TypeAdapter<List<User>> typeAdapter = new TypeAdapter<List<User>>() {
            @Override
            public void write(JsonWriter jsonWriter, List<User> users) throws IOException {
//                    省略
            }

            @Override
            public List<User> read(JsonReader jsonReader) throws IOException {
                List<User> 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<User> list = new ArrayList<>();
        list.add(new User("a",11,"123456@qq.com"));
        list.add(new User("b",22,"789456@qq.com"));
        System.out.println(list);
        String result = gson.toJson(list, type);//明确指定type时才会使用注册的TypeAdapter托管序列化和反序列化
        System.out.println(result);
        //[User{name='a', age=11, email='123456@qq.com'}, User{name='b', age=22, email='789456@qq.com'}]
        String result2 = gson.toJson(list);//不指定type时使用系统默认的机制进行序列化和反序列化
        System.out.println(result2);
        //[{"name":"a","age":11,"email":"123456@qq.com"},{"name":"b","age":22,"email":"789456@qq.com"}]
    }

三、TypeAdapterFactory

解释:用于生产TypeAdapter的工厂类。
通过对比Type,确定有没有对应的TypeAdapter,没有就返回null,与GsonBuilder.registerTypeAdapterFactory配合使用。

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new TypeAdapterFactory() {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> 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<List<?>>() {
    @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();
上一篇下一篇

猜你喜欢

热点阅读