JSON解析类库之Gson(3) --- Gson注解

xiaoxiao2021-02-28  160

JSON解析类库之Gson(3) --- Gson注解

---Gson类库学习, 生成与解析json数据,json字符串与Java对象互转

一、前言 Gson注解给我们的使用带来很多方便,特别是Java实体类字段与获得的JSON字符串的字段不一一对应时,注解发挥巨大作用,同时也简化了代码的开发。 二、Gson的注解 注:在Gson中有5类注解  。   ◆ 1   @SerializedName注解(JSON字段重命名) ---------------------------------------------------------------------------------------------------- 该注解能指定该字段在JSON中对应的字段名称,就是将POJO中的字段与JSON字符串中的字段对应起来。 输出的json使用另外一个名字,默认转换出来的json中和对象的字段是一样的,当然也 可以设置成不同,使用SerializedName 注解 。 作用1:转换关键字key,json转换成JavaBean时,json字段的key 默认必须和我们声明类的字段名称一样,当服务器端返回了关键字怎么办,比如key 为new switch这样,我们在声明类的时候不能写这样的字段,可能你想服务器端改动,他可能要改数据库,但是我告诉你,做服务端的大部分不愿意改动他的json,是很自私的!这时候重命名注解都排上用场了 。  第二种场景:服务器端返回的json 的key 简直太丑,或者太长,你想简化,my_parent_name,可以简化成mpn 。 从前面的POJO的生成与解析可以看出,json的字段和值是和pojo的名称和类型是一一对应的,但也有一定容错机制(如第一篇文章中,基本类型转换中,第3行将字符串的99.99转成double型,你可别告诉我都是字符串啊),但有时候也会出现一些不和谐的情况,如: 期望的json格式 {"id":"100",name":"chunlynn","emailAddress":"chunlynn@example.com","title":"engineer"} 实际 {"id":"100",name":"chunlynn","email_address":"chunlynn@example.com","title":"engineer"} 如果我们是通过http调用其他系统的接口而获得到的JSON字符串数据,显然JSON字符串的结果我们是无法改变的,而JSON的字段和我们的POJO中字段并没有一一对应,这样解析肯定会出错。这些以下划线命名的方式,在使用PHP作为后台开发语言时是很常见的情况,php和js在命名时一般采用下划线风格,而Java中一般采用的驼峰法,若要自己使用下划线风格时我会感到不适应,且不符合Java命名规范,怎么办?难到没有两全齐美的方法么? Gson提供了一个 SerializedName的注解类,这应该就是我们要找的。 那么对于JSON中email_address这个字段对应POJO的字段则变成: @SerializedName( "email_address" ) private String emailAddress; 这样的话,很好的保留了前端、后台、Java/Android各自的命名习惯。 注意: SerializedName中的value属性值,永远都是指JSON字符串中的字段值(POJO序列化后的值)。如 email_address指的就是JSON字符串中的字段值,通过注解@ SerializedName("email_address")将它和POJO中的字段值emailAddress关联映射起来。 你以为这样就完了么? 如果接口中设计不严谨,或者其它地方可以重用该类,其它字段都一样,就emailAddress 字段不一样,比如有下面三种情况那怎么?重新写一个? {"id":"100",name":"chunlynn","emailAddress":"chunlynn@example.com","title":"engineer"} {"id":"100",name":"chunlynn","email_address":"chunlynn@example.com","title":"engineer"} {"id":"100",name":"chunlynn","email":"chunlynn@example.com","title":"engineer"} 为POJO字段提供备选属性名 SerializedName注解提供了两个属性,上面用到了其中一个,别外还有一个属性alternate,接收一个String数组。 注:alternate需要2.4及以上版本。 alternate是反序列化时才有用。不管 SerializedName中的值是多少,反序列化后对应的POJO的字段值都是emailAddress。 @SerializedName(value   =   "emailAddress",   alternate   =   {   "email",   "email_address"   }) private String emailAddress; 如果JSON中有 email 就会解析成 emailAddress ,如果有 email_address 也会解析成 emailAddress. 注意1:value中的值不能出现在alternate中; 注意2:alternate的备选字段, 会后面的替换前面的。 当上面的三个属性(email_address、email、emailAddress)中都出现,或出现任意一个时均可以得到正确的结果。 注:当多种情况同时出时,以最后一个出现的值为准。 情况1: 实体类: import  com.google.gson.annotations.SerializedName; public class Employee {     private String id;     private String name;     @SerializedName(value = "emailAddress", alternate = { "email", "email_address" })     private String emailAddress; //为了代码简洁,这里移除了getter和setter方法、toString方法等       } 测试类【反序列化】: package  com.chunlynn.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class GsonTest12 {     public static void main(String[] args) {         Gson gson = new GsonBuilder()//                 //.setPrettyPrinting()//格式化输出(序列化)                 .enableComplexMapKeySerialization() 支持Map的key为复杂对象的形式                 .create();         /*         {\"id\":\"100\",\"name\":\"chunlynn\",\"emailAddress\":\"chunlynn@example.com\"}         {\"id\":\"100\",\"name\":\"chunlynn\",\"email_address\":\"chunlynn@example.com\"}         {\"id\":\"100\",\"name\":\"chunlynn\",\"email\":\"chunlynn@example.com\"}         */         String json1 = "{\"id\":\"100\",\"name\":\"chunlynn\",\"email_address\":\"chunlynn@example.com\"}";         String json2 = "{\"id\":\"100\",\"name\":\"chunlynn\",\"emailAddress\":\"chunlynn@example.com\",\"email_address\":\"chunlynn@example.com\",\"email\":\"chunlynn@example.com\"}";         Employee employee1 = gson.fromJson(json1, Employee.class);         System.out.println("email_address字段反序列化 ===> " + employee1);         //email_address字段反序列化 ===> Employee [id=100, name=chunlynn, emailAddress=chunlynn@example.com]         Employee employee2 = gson.fromJson(json2, Employee.class);         System.out.println("多种格式字段反序列化 ===> " + employee2);         // 多种格式字段反序列化 ===> Employee [id=100, name=chunlynn, emailAddress=chunlynn@example.com]     } } 结果反序列化完全成功。这个注解在我们处理调用的远程接口返回的JSON字段与我们自己定义的POJO的字段不匹配时非常有用。 情况2: 实体类: public   class  Employee {     private String id;     private String name; //序列化后就变成了email (json串中的字段名)      @SerializedName(value   =   "email",   alternate   =   {   "emailAddress",   "email_address"   })     private String emailAddress;     //为了代码简洁,这里移除了getter和setter方法、toString方法、构造方法等 } 测试类【序列化与反序列化】: package  com.chunlynn.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class GsonTest13 {     public static void main(String[] args) {         Gson gson = new GsonBuilder()//                 //.setPrettyPrinting()//格式化输出(序列化)                 .enableComplexMapKeySerialization() 支持Map的key为复杂对象的形式                 .create();         Employee empyee = new Employee("1001", "jeffchen", "jeff@126.com");         String jsonString = gson.toJson(empyee);         System.out.println("使用注解后的序列化==" + jsonString);         // 使用注解后的序列化=={"id":"1001","name":"jeffchen","email":"jeff@126.com"}         Employee employee3 = gson.fromJson(jsonString, Employee.class);         System.out.println("使用注解后的反序列化==" + employee3);         // 使用注解后的反序列化==Employee [id=1001, name=jeffchen, emailAddress=jeff@126.com]     } } ◆ 2   @Expose注解(字段过滤) ---------------------------------------------------------------------------------------------------- 指定哪些是要暴露转换的属性。有时候我们不需要把实体的所有属性都导出,只想把一部分属性导出为Json,或只想对一部分POJO的字段进行反序列化。 源码:默认既可以序列化又可以反序列化。下面是Gson的 Expose 注解源码: @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Expose {       public   boolean   serialize()   default   true;    public boolean deserialize() default true; } Expose注解有两个属性,默认值都是true,即默认同时对序列化和反序列化都有效。 即使用了Expose默认注解后:标注了 Expose注解的字段才会被序列化输出,同时,反序列化时,标注了 Expose注解的字段才会被反序列化。 情况1:默认注解  @Expose ,序列化和反序列化都有效 实体类: import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; public   class  Employee2 {     private String id; @Expose //等同于@Expose(deserialize = true,serialize = true)        private   String   name; @ Expose //序列化后就变成了email (json串中的字段名)     @SerializedName(value = "email", alternate = { "emailAddress", "email_address" })     private String emailAddress;     private Date birthday;      @ Expose     private String title; //为了代码简洁,这里移除了getter和setter方法、toString方法、构造方法等     }

测试类: 注意使用了@Expose注解,则必须在GsonBuilder类实例化时进行设置。只有配置了 .excludeFieldsWithoutExposeAnnotation() 时,@Expose才会起作用。 package  com.chunlynn.gson; import java.util.Date; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class GsonTest14 {     public static void main(String[] args) {         Gson gson = new GsonBuilder()//                 //.setPrettyPrinting()//格式化输出(序列化)                 .excludeFieldsWithoutExposeAnnotation() // 不导出实体中没有用@Expose注解的属性。                 .setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化时间转化为特定格式                   .create();         Employee2 employee2 = new Employee2("1002", "chunlynn", "chunlynn@163.com", new Date(), "engineer");         String jsonString = gson.toJson(employee2);         System.out.println("使用了@Expose注解后的序列化输出 ===》 " + jsonString);         //使用了@Expose注解后的序列化输出 ===》 {"name":"chunlynn","email":"chunlynn@163.com","title":"engineer"}         Employee2 retEmployee = gson.fromJson(jsonString, Employee2.class);         System.out.println("使用了@Expose注解后的反序列化解析==》" + retEmployee);         //使用了@Expose注解后的反序列化解析==》Employee2 [id=null, name=chunlynn, emailAddress=chunlynn@163.com, birthday=null, title=engineer]         String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"jeff@163.com\",\"title\":\"boss\"}";         Employee2 reEmployee2 = gson.fromJson(jsonString2, Employee2.class);         System.out.println("使用了@Expose注解后的反序列化解析2==》" + reEmployee2);         // 使用了@Expose注解后的反序列化解析2==》Employee2 [id=null, name=jeffchen, emailAddress=jeff@163.com, birthday=null, title=boss]     } } 上面的实体类中,我们使用的是@Expose的默认属性,默认情况下对序列化和反序列化都有效。 Expose注解类两个属性:serialize和deserialize可以分别设置序列化和反序列化。  分为以下几种情况: 1:不添加@Expose注解等同于@Expose(deserialize = false,serialize = false) 不做任何解析。 2:@Expose(deserialize = true,serialize = false) 只解析时用,也就是反序列化可以,序列化不可以 3:@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行 4:@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化,等同于默认。 下面实例,将分别演示这四种情况。 情况2:分别设置序列化与反序列化暴露字段 实体类: public   class  Employee3 {     private String id;     @Expose //等同于 @Expose(deserialize = true,serialize = true)       private String name;     @Expose     @SerializedName(value = "email", alternate = { "emailAddress", "email_address" })     private String emailAddress;     @Expose(serialize = true, deserialize = false)     private Date birthday; @Expose(serialize = false, deserialize = true)      private   String   title; //为了代码简洁,这里移除了getter和setter方法、toString方法、构造方法等 } 测试类: package  com.chunlynn.gson; import java.util.Date; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class GsonTest15 {     public static void main(String[] args) {         Gson gson = new GsonBuilder()//                 //.setPrettyPrinting()//格式化输出(序列化)                 .excludeFieldsWithoutExposeAnnotation() // 不导出实体中没有用@Expose注解的属性                  .setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化时间转化为特定格式                   .create();         Employee3 employee3 = new Employee3("1005", "chunlynn", "chunlynn@163.com", new Date(), "engineer");         /**          * 序列化          */         String jsonStr = gson.toJson(employee3);         System.out.println("使用@Expose()注解后的序列化输出 ==》 " + jsonStr);         //使用了@Expose注解后的序列化输出 ===》  //{"name":"chunlynn","email":"chunlynn@163.com","birthday":"2017-05-05 11:20:36"}         /**          * 反序列化[1]          */         Employee3 retEmployee = gson.fromJson(jsonStr, Employee3.class);         System.out.println("使用了@Expose()注解后的反序列化解析==》" + retEmployee);         //使用了@Expose()注解后的反序列化解析==》 //Employee3 [id=null, name=chunlynn, emailAddress=chunlynn@163.com, birthday=null, title=null]         /**          * 反序列化[2]          */         String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"jeff@163.com\",\"title\":\"boss\"}";         Employee3 reEmployee2 = gson.fromJson(jsonString2, Employee3.class);         System.out.println("使用了@Expose()注解后的反序列化解析2==》" + reEmployee2);         // 使用了@Expose()注解后的反序列化解析2==》 //Employee3 [id=null, name=jeffchen, emailAddress=jeff@163.com, birthday=null, title=boss]     } } ◆ 3、4   @Since(double v) 与 @Until(double v)注解 (版本控制) ---------------------------------------------------------------------------------------------------- 有时候我们的实体类会随着版本的升级而修改。一些新的字段是后续加进来的,在新的版本软件中才使用。 @Since(double v) 与 @Until(double v)注解源码: @Retention (RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Since {   /**    * the value indicating a version number since this member    * or type has been present.    */   double value(); } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Until {   /**    * the value indicating a version number until this member    * or type should be ignored.    */   double value(); } @Since  和  @Until 都接收一个 Double 值。 Since(4.0),表示当前版本大于等于4.0时才有效。当前版本是指在GsonBuilder.setVersion(double v)中设置的版本。 Until(4.0),表示当前版本小于4.0时才有效。 实体类: public   class  Employee4 {     private String id;     @Expose     //等同于 @Expose(deserialize = true,serialize = true)       private String name;     @Expose     @SerializedName(value = "email", alternate = { "emailAddress", "email_address" })     private String emailAddress;     @Expose(serialize = true, deserialize = false)     private Date birthday;     @Expose(serialize = false, deserialize = true)     private String title; @Expose     @Since(4.0) //表示该字段从4.0开始生效     private String phoneNum; @Expose     @Until(2.0) //表示2.0及其以后该字段就失效了     private String habbit;   //为了代码简洁,这里移除了getter和setter方法、toString方法、构造方法等 } 测试类: 注意使用了@Since(double v)、@Until(double v)注解,则必须在GsonBuilder类实例化时进行设置。只有配置了 .setVersion(double v) 时,@Since(double v)、@Until(double v)才会起作用。 package  com.chunlynn.gson; import java.util.Date; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class GsonTest16 {     public static void main(String[] args) {         Gson gson = new GsonBuilder()//                 //.setPrettyPrinting()//格式化输出(序列化)                 .excludeFieldsWithoutExposeAnnotation() // 不导出实体中没有用@Expose注解的属性                  .setDateFormat("yyyy-MM-dd HH:mm:ss") //序列化时间转化为特定格式                   .setVersion(5.0) //设置当前版本号                 .create();         Employee4 employee = new Employee4("1005", "chunlynn", "chunlynn@163.com", new Date(), "engineer", "10086",                 "羽毛球");         /**          * 序列化          */         String jsonStr = gson.toJson(employee);         System.out.println("使用@Since()和@Until()注解后的序列化输出 ==》 " + jsonStr);         //使用@Since()和@Until()注解后的序列化输出 ==》          //{"name":"chunlynn","email":"chunlynn@163.com","birthday":"2017-05-05 11:52:40","phoneNum":"10086"}         /**          * 反序列化[3]          */         Employee4 retEmployee = gson.fromJson(jsonStr, Employee4.class);         System.out.println("使用@Since()和@Until()注解后的反序列化解析==》" + retEmployee);         //使用@Since()和@Until()注解后的反序列化解析==》         //Employee4 [id=null, name=chunlynn, emailAddress=chunlynn@163.com, birthday=null, title=null, phoneNum=10086, habbit=null]         /**          * 反序列化[4]          */         String jsonString2 = "{\"id\":\"1007\",\"name\":\"jeffchen\",\"email\":\"jeff@163.com\",\"title\":\"boss\",\"phoneNum\":\"10010\",\"habbit\":\"游泳\"}";         Employee4 reEmployee2 = gson.fromJson(jsonString2, Employee4.class);         System.out.println("使用@Since()和@Until()注解后的反序列化解析2==》" + reEmployee2);         //使用@Since()和@Until()注解后的反序列化解析2==》         //Employee4 [id=null, name=jeffchen, emailAddress=jeff@163.com, birthday=null, title=boss, phoneNum=10010, habbit=null]     } } ◆ 5   JsonAdapter 注解 (使用TypeAdapter时的注解) ---------------------------------------------------------------------------------------------------- 该注解在TypeAdapter的章节中进行讲解,不过一般很少用这个注解。 注解讲解完。 该系列的其他文章 JSON解析类库之Gson(1) --- 简单JavaBean对象、带泛型的Bean对象与JSON互转 JSON解析类库之Gson(2) --- 泛型对象Map、List与JSON字符串互转 JSON解析类库之Gson(3) --- Gson注解 JSON解析类库之Gson(4)--- TypeAdapter接管序列化与反序列化(上) --------------------------------------------------------------------------------------------------- 版权声明:本文为博主(chunlynn)原创文章,转载请注明出处 :http://blog.csdn.net/chenchunlin526/article/details/71173404

转载请注明原文地址: https://www.6miu.com/read-22295.html

最新回复(0)