美文网首页
Gson学习-4

Gson学习-4

作者: 盼旺 | 来源:发表于2019-09-19 13:46 被阅读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();
    

    相关文章

      网友评论

          本文标题:Gson学习-4

          本文链接:https://www.haomeiwen.com/subject/wtqructx.html