美文网首页
★36.Gson

★36.Gson

作者: iDragonfly | 来源:发表于2017-06-29 00:06 被阅读0次

    简介

    基本类型示例

    // 创建Gson对象
    Gson gson = new Gson();
    
    // 反序列化
    int a1 = gson.fromJson("1", int.class);                             // ==> 1
    Integer a2 = gson.fromJson("1", Integer.class);                     // ==> 1
    Long a3 = gson.fromJson("1", Long.class);                           // ==> 1
    Boolean a4 = gson.fromJson("false", Boolean.class);                 // ==> false
    String a5 = gson.fromJson("\"abc\"", String.class);                 // ==> "abc"
    String[] a6 = gson.fromJson("[\"abc\", \"def\"]", String[].class);  // ==> {"abc", "def"}
    
    // 序列化
    String s1 = gson.toJson(1);            // ==> "1"
    String s2 = gson.toJson("abcd");       // ==> "\"abcd\""
    String s3 = gson.toJson(10L);          // ==> "10"
    int[] values = {1};
    String s4 = gson.toJson(values);       // ==> "[1]"
    

    对象示例

    代码

    class A {
        private String name = "Tim";
        private int age = 18;
        private boolean isStudent = true;
        private String sex = "male";
        private String[] girlFriends = { "Alice", "Amy", "Mary" };
        private B Alice = new B();  // 尽管没有这句,内部类也会有实例,但是没有这句,就不会序列化或反序列化。
        class B {
            private String name = "Alice";
            private int age = 17;
            private boolean isStudent = true;
            private String sex = "female";
            private String boyFriend = "Tim";
            private B() {}
        }
    }
    
    Gson gson = new Gson();
    // 序列化
    A a1 = new A();
    String json = gson.toJson(a1);
    // 反序列化
    A a2 = gson.fromJson(json, A.class);
    

    一些细节

    • 最好使用private访问控制。
    • 默认情况下,所有字段都会被序列化或反序列化。
    • 如果字段被标记为@transient,则不会被序列化或反序列化。
    • 能正确地处理null的情况:
      • 序列化:null字段被跳过。
      • 反序列化:缺失的字段会被设置为null
    • 如果字段是synthetic的,则不会进行序列化或反序列化。
    • 在字段前加上@SerializedName("name")可以改变序列化的名字。

    泛型示例

    下面例子展示了如何从java数组转换成List<String>,直接使用List<String>.class是不可行的,必须使用TypeToken

    Gson gson = new Gson();
    String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
    String[] strings = gson.fromJson(jsonArray, String[].class);
    List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
    

    注:TypeToken的构造方法是protected修饰的,所以上面才会写成new TypeToken<List<String>>() {}.getType()而不是new TypeToken<List<String>>().getType(),先继承后使用。

    Gson 可以序列化或反序列化以下泛型类,但是提供类型信息时需要像上述那样提供TypeToken

    public class Result<T> {
        public int code;
        public String message;
        public T data;
    }
    

    流式序列化与反序列化

    流式反序列化

    自动方式

    直接将 JavaReader当做String来使用。

    Gson.toJson(Object);
    Gson.fromJson(Reader,Class);
    Gson.fromJson(String,Class);
    Gson.fromJson(Reader,Type);
    Gson.fromJson(String,Type);
    

    手动方式

    通过JsonReader来逐个反序列化。

    String json = "{\"name\":\"Tim\",\"age\":\"24\"}";
    User user = new User();
    JsonReader reader = new JsonReader(new StringReader(json));
    reader.beginObject(); // throws IOException
    while (reader.hasNext()) {
        String s = reader.nextName();
        switch (s) {
            case "name":
                user.name = reader.nextString();
                break;
            case "age":
                user.age = reader.nextInt(); //自动转换
                break;
            case "email":
                user.email = reader.nextString();
                break;
        }
    }
    reader.endObject(); // throws IOException
    System.out.println(user.name);  // Tim
    System.out.println(user.age);   // 24
    System.out.println(user.email); // Tim@example.com
    

    流式序列化

    自动方式

    Gson gson = new Gson();
    User user = new User("Tim",24,"Tim@example.com");
    gson.toJson(user,System.out); // 写到控制台
    

    手动方式

    JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out));
    writer.beginObject() // throws IOException
            .name("name").value("Tim")
            .name("age").value(24)
            .name("email").nullValue() //演示null
            .endObject(); // throws IOException
    writer.flush(); // throws IOException
    //{"name":"Tim","age":24,"email":null}
    

    注:除了beginObject()endObject()还有beginArray()endArray(),两者可以相互嵌套,注意配对即可。beginArray()后不可以调用name(),同样beginObject()后在调用value()之前必须要调用name()

    GsonBuilder

    Gson 在默认情况下是不序列化值为null的字段的,可以通过GsonBuilder改变配置。

    public class User {
        public String name;
        public int age;
        public String email;
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    Gson gson = new GsonBuilder()
            //序列化null
            .serializeNulls()
            // 设置日期时间格式,另有2个重载方法
            // 在序列化和反序化时均生效
            .setDateFormat("yyyy-MM-dd")
            // 禁此序列化内部类
            .disableInnerClassSerialization()
            //生成不可执行的Json
            .generateNonExecutableJson()
            //禁止转义html标签
            .disableHtmlEscaping()
            //格式化输出
            .setPrettyPrinting()
            .create();
    User user = new User("Tim", 24);
    System.out.println(gson.toJson(user)); //{"name":"Tim","age":24,"email":null}
    

    普通过滤字段

    通过@Expose注解标注要序列化或反序列化的字段,只在使用GsonBuilder,且设置了excludeFieldsWithoutExposeAnnotation()时生效

    @Expose //序列化和反序列化都都生效
    @Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效
    @Expose(deserialize = true,serialize = false) //反序列化时生效
    @Expose(deserialize = false,serialize = true) //序列化时生效
    @Expose(deserialize = false,serialize = false) // 和不写一样
    
    public class Category {
        @Expose public int id;
        @Expose public String name;
        @Expose public List<Category> children;
        //不需要序列化,所以不加 @Expose 注解,
        //等价于 @Expose(deserialize = false,serialize = false)
        public Category parent;
    }
    
    Gson gson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .create();
    gson.toJson(category);
    

    基于版本过滤字段

    使用@Since@Until来标记版本,在使用GsonBuilder且设置setVersion()时生效。

    class SinceUntilSample {
        @Since(4)
        public String since;
        @Until(5)
        public String until;
    }
    
    SinceUntilSample sinceUntilSample = new SinceUntilSample();
    sinceUntilSample.since = "since";
    sinceUntilSample.until = "until";
    Gson gson = new GsonBuilder().setVersion(version).create();
    System.out.println(gson.toJson(sinceUntilSample));
    

    注:当一个字段被同时注解时,需两者同时满足条件。

    基于访问控制符过滤字段

    只有在调用了GsonBuilderexcludeFieldsWithModifiers()时生效。

    class ModifierSample {
        final String finalField = "final";
        static String staticField = "static";
        public String publicField = "public";
        protected String protectedField = "protected";
        String defaultField = "default";
        private String privateField = "private";
    }
    
    ModifierSample modifierSample = new ModifierSample();
    Gson gson = new GsonBuilder()
            .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
            .create();
    System.out.println(gson.toJson(modifierSample));
    // 结果:{"publicField":"public","protectedField":"protected","defaultField":"default"}
    

    基于策略过滤字段

    Gson gson = new GsonBuilder()
            .addSerializationExclusionStrategy(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    // 这里作判断,决定要不要排除该字段,return true为排除
                    if ("finalField".equals(f.getName())) return true; //按字段名排除
                    Expose expose = f.getAnnotation(Expose.class);
                    if (expose != null && expose.deserialize() == false) return true; //按注解排除
                    return false;
                }
                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    // 直接排除某个类 ,return true为排除
                    return (clazz == int.class || clazz == Integer.class);
                }
            })
            .create();
    

    Java对象与Json字段映射规则

    @SerializedName注解

    可以在字段前加上@SerializedName注解来定义序列化或反序列化的名字。

    // value为默认名字
    // alternate为可选名字
    @SerializedName(value = "name", alternate = {"name1", "name2"})
    

    若同时出现多个匹配的名字,即 Json 字符串中包含"name""name1""name3"时,以 Json 最后出现的为准。

    通过FieldNamingPolicy

    对于emailAddress字段,选用不同的FieldNamingPolicy,会映射不同的 Json 字段。

    FieldNamingPolicy 结果(仅输出emailAddress字段)
    IDENTITY(默认与java字段名一致) {"emailAddress":"Tim@example.com"}
    LOWER_CASE_WITH_DASHES {"email-address":"Tim@example.com"}
    LOWER_CASE_WITH_UNDERSCORES {"email_address":"Tim@example.com"}
    UPPER_CAMEL_CASE {"EmailAddress":"Tim@example.com"}
    UPPER_CAMEL_CASE_WITH_SPACES {"Email Address":"Tim@example.com"}
    A a = new A();
    Gson gson = new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
            .create();
    String json = gson.toJson(a);
    

    通过FieldNamingStrategy

    通过实现通过FieldNamingStrategy接口的方式:

    Gson gson = new GsonBuilder()
            .setFieldNamingStrategy(new FieldNamingStrategy() {
                @Override
                public String translateName(Field f) {
                    //实现自己的规则
                    return null;
                }
            })
            .create();
    

    注意: @SerializedName注解拥有最高优先级,在加有@SerializedName注解的字段上FieldNamingStrategy不生效!

    定制性最高的方式:使用TypeAdapter

    TypeAdapter是用于用于接管某种类型的序列化和反序列化过程。包含两个主要方法write(JsonWriter,T)read(JsonReader)其它的方法都是final方法并最终调用这两个抽象方法。

    注册TypeAdapter

    本例中只接管User类的序列化和反序列化,也可以只接管Integer类型等。

    User user = new User("Tim", 24);
    user.emailAddress = "Tim@example.com";
    Gson gson = new GsonBuilder()
            //定制User类型的序列化或反序列化,通过使用UserTypeAdapter(继承了TypeAdapter)。
            .registerTypeAdapter(User.class, new UserTypeAdapter())
            .create();
    System.out.println(gson.toJson(user));
    

    定义UserTypeAdapter

    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("email").value(value.email);
            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 "email":
                    case "email_address":
                    case "emailAddress":
                        user.email = in.nextString();
                        break;
                }
            }
            in.endObject();
            return user;
        }
    }
    

    JsonSerializer 与 JsonDeserializer

    注册TypeAdapter必须要同时定制序列化和反序列化,但是可以使用JsonSerializerJsonDeserializer来定制其中之一。

    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();
    System.out.println(gson.toJson(100)); //结果:100
    System.out.println(gson.fromJson("\"\"", Integer.class)); //结果-1
    
    // 数字转字符串
    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)
            .registerTypeAdapter(Long.class, numberJsonSerializer)
            .registerTypeAdapter(Float.class, numberJsonSerializer)
            .registerTypeAdapter(Double.class, numberJsonSerializer)
            .create();
    System.out.println(gson.toJson(100.0f));//结果:"100.0"
    

    TypeAdapter 与 JsonSerializer、JsonDeserializer 比较

    TypeAdapter JsonSerializer、JsonDeserializer
    引入版本 2.0 1.x
    Stream API 支持 不支持,需要提前生成JsonElement
    内存占用 比TypeAdapter大
    效率 比TypeAdapter低
    作用范围 序列化 反序列化 序列化 反序列化

    registerTypeAdapter 与 registerTypeHierarchyAdapter 的区别

    区别

    registerTypeAdapter registerTypeHierarchyAdapter
    支持泛型
    支持继承

    使用registerTypeAdapter的泛型例子

    注:如果一个被序列化的对象本身就带有泛型,且注册了相应的TypeAdapter,那么必须调用Gson.toJson(Object,Type),明确告诉 Gson 对象的类型。

    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));
    //注意,多了个type参数
    String result = gson.toJson(list, type);
    

    使用registerTypeHierarchyAdapter的泛型例子

    缺失。

    // 数字转字符串
    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)
            .registerTypeAdapter(Long.class, numberJsonSerializer)
            .registerTypeAdapter(Float.class, numberJsonSerializer)
            .registerTypeAdapter(Double.class, numberJsonSerializer)
            .create();
    System.out.println(gson.toJson(100.0f));//结果:"100.0"
    

    注:上面的IntegerLongFloatDouble必须分别注册,不能使用这4个类的父类取代,除非使用registerTypeHierarchyAdapter而非registerTypeAdapter

    TypeAdapterFactory

    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) {
                return null;
            }
        })
        .create();
    

    @JsonAdapter注解

    JsonAdapter接收一个参数,且必须是TypeAdpaterJsonSerializerJsonDeserializer这三个其中之一。使用了JsonAdapter就不用每次使用GsonBuilder去注册UserTypeAdapter了。

    注意:JsonAdapter的优先级比GsonBuilder.registerTypeAdapter()的优先级更高。

    @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;
    }
    

    相关文章

      网友评论

          本文标题:★36.Gson

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