JSON解析类库之Gson(3) --- Gson注解
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json
免费下载资源
·
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;@ Exposeprivate 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的章节中进行讲解,不过一般很少用这个注解。
注解讲解完。
◆
◆
该系列的其他文章
:
---------------------------------------------------------------------------------------------------
版权声明:本文为博主(chunlynn)原创文章,转载请注明出处 :http://blog.csdn.net/chenchunlin526/article/details/71173404
GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e
4 个月前
8c391e04
6 个月前
更多推荐
已为社区贡献13条内容
所有评论(0)