/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class User {
private String name;
private int age;
private boolean sex;
public User(String name, int age, boolean sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return “User{” +
“name='” + name + ‘’’ +
“, age=” + age +
“, sex=” + sex +
‘}’;
}
}
序列化的方法很简单,调用 gson 对象的 toJson 方法,传入要序列化的对象
public static void main(String[] args) {
//序列化
User user = new User(“leavesC”, 24, true);
Gson gson = new Gson();
System.out.println();
System.out.println(gson.toJson(user));
}
反序化的方式也类似
public static void main(String[] args) {
//反序列化
String userJson = “{“name”:“leavesC”,“age”:24,“sex”:true}”;
Gson gson = new Gson();
User user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
}
二、属性重命名
继续使用上一节声明的 User 类,根据 User 类声明的各个属性名,移动端的开发者希望接口返回的数据格式即是如下这样的
{“name”:“leavesC”,“age”:24,“sex”:true}
如果没有和服务器端沟通好或者是 API 改版了,接口返回的数据格式可能是这样的
{“Name”:“leavesC”,“age”:24,“sex”:true}
{“userName”:“leavesC”,“age”:24,“sex”:true}
如果继续使用上一节介绍的方法,那无疑会解析出错 例如
public static void main(String[] args) {
//反序列化
String userJson = “{“userName”:“leavesC”,“age”:24,“sex”:true}”;
Gson gson = new Gson();
User user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
}
name 属性值解析不到,所以为 null
此时为了兼顾多种格式的数据,就需要使用 SerializedName 注解 根据 SerializedName 的声明来看,SerializedName 包含两个属性值,一个是字符串,一个是字符串数组,而字符串数组含有默认值
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface SerializedName {
String value();
String[] alternate() default {};
}
SerializedName 的作用是为了在序列化或反序列化时,指导 Gson 如果将原有的属性名和其它特殊情况下的属性名联系起来
例如,修改 User 类,为 name 声明 SerializedName 注解,注解值为 userName
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class User {
@SerializedName(“userName”)
private String name;
private int age;
private boolean sex;
}
在序列时,Json 格式就会相应改变
public static void main(String[] args) {
//序列化
User user = new User(“leavesC”, 24, true);
Gson gson = new Gson();
System.out.println();
System.out.println(gson.toJson(user));
}
在反序列化时也一样,能够解析到正确的属性值
public static void main(String[] args) {
//反序列化
String userJson = “{“userName”:“leavesC”,“age”:24,“sex”:true}”;
Gson gson = new Gson();
User user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
}
还有个问题没解决,为了应对多种属性名不一致的情况,难道我们要声明多个 User 类吗?这显然是不现实的,所以还需要为 User 类设置多个备选属性名,这就需要用到 SerializedName 注解的另一个属性值 alternate 了。
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class User {
@SerializedName(value = “userName”, alternate = {“user_name”, “Name”})
private String name;
private int age;
private boolean sex;
}
以下几种情况都能够被正确的反序列化
public static void main(String[] args) {
//反序列化
Gson gson = new Gson();
String userJson = “{“userName”:“leavesC”,“age”:24,“sex”:true}”;
User user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
userJson = “{“user_name”:“leavesC”,“age”:24,“sex”:true}”;
user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
userJson = “{“Name”:“leavesC”,“age”:24,“sex”:true}”;
user = gson.fromJson(userJson, User.class);
System.out.println();
System.out.println(user);
}
三、字段过滤
有时候并不是所有的字段都需要进行系列化和反序列化,因此需要对某些字段进行排除,有四种方法可以来实现这种需求。
3.1、基于@Expose注解
Expose 注解包含两个属性值,且均声明了默认值。Expose 的含义即为“暴露”,即用于对外暴露字段,serialize 用于指定是否进行序列化,deserialize 用于指定是否进行反序列化。如果字段不声明 Expose 注解,则意味着不进行序列化和反序列化操作,相当于两个属性值均为 false 。此外,Expose 注解需要和 GsonBuilder 构建的 Gson 对象一起使用才能生效。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Expose {
boolean serialize() default true;
boolean deserialize() default true;
}
Expose 注解的注解值声明情况有四种
@Expose(serialize = true, deserialize = true) //序列化和反序列化都生效
@Expose(serialize = false, deserialize = true) //序列化时不生效,反序列化时生效
@Expose(serialize = true, deserialize = false) //序列化时生效,反序列化时不生效
@Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样
现在来看个例子,修改 User 类
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class User {
@Expose(serialize = true, deserialize = true) //序列化和反序列化都生效
private String a;
@Expose(serialize = false, deserialize = true) //序列化时不生效,反序列化时生效
private String b;
@Expose(serialize = true, deserialize = false) //序列化时生效,反序列化时不生效
private String c;
@Expose(serialize = false, deserialize = false) //序列化和反序列化都不生效,和不写注解一样
private String d;
private String e;
public User(String a, String b, String c, String d, String e) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
@Override
public String toString() {
return “User{” +
“a='” + a + ‘’’ +
“, b='” + b + ‘’’ +
“, c='” + c + ‘’’ +
“, d='” + d + ‘’’ +
“, e='” + e + ‘’’ +
‘}’;
}
}
按照如上的注解值,只有声明了 Expose 注解且 serialize 值为 true 的字段才能被序列化,只有声明了 Expose 注解且 deserialize 值为 true 的字段才能被反序列化
public static void main(String[] args) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
User user = new User(“A”, “B”, “C”, “D”, “E”);
System.out.println();
System.out.println(gson.toJson(user));
String json = “{“a”:“A”,“b”:“B”,“c”:“C”,“d”:“D”,“e”:“E”}”;
user = gson.fromJson(json, User.class);
System.out.println();
System.out.println(user.toString());
}
3.2、基于版本
Gson 提供了 @Since 和 @Until 两个注解基于版本对字段进行过滤,@Since 和 @Until 都包含一个 Double 属性值,用于设置版本号。Since 的意思是“自……开始”,Until 的意思是“到……为止”,一样要和 GsonBuilder 配合使用。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Since {
double value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Until {
double value();
}
当版本( GsonBuilder 设置的版本) 大于或等于 Since 属性值或小于 Until 属性值时字段会进行序列化和反序列化操作,而没有声明注解的字段都会加入序列化和反序列操作
现在来看个例子,修改 User 类
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class User {
@Since(1.4)
private String a;
@Since(1.6)
private String b;
@Since(1.8)
private String c;
@Until(1.6)
private String d;
@Until(2.0)
private String e;
public User(String a, String b, String c, String d, String e) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
@Override
public String toString() {
return “User{” +
“a='” + a + ‘’’ +
“, b='” + b + ‘’’ +
“, c='” + c + ‘’’ +
“, d='” + d + ‘’’ +
“, e='” + e + ‘’’ +
‘}’;
}
}
public static void main(String[] args) {
Gson gson = new GsonBuilder().setVersion(1.6).create();
User user = new User(“A”, “B”, “C”, “D”, “E”);
System.out.println();
System.out.println(gson.toJson(user));
String json = “{“a”:“A”,“b”:“B”,“c”:“C”,“d”:“D”,“e”:“E”}”;
user = gson.fromJson(json, User.class);
System.out.println();
System.out.println(user.toString());
}
3.3、基于访问修饰符
访问修饰符由 java.lang.reflect.Modifier 提供 int 类型的定义,而 GsonBuilder 对象的 excludeFieldsWithModifiers
方法接收一个 int 类型可变参数,指定不进行序列化和反序列化操作的访问修饰符字段 看个例子
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class ModifierSample {
public String publicField = “public”;
protected String protectedField = “protected”;
private String privateField = “private”;
String defaultField = “default”;
final String finalField = “final”;
static String staticField = “static”;
}
public static void main(String[] args) {
Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC).create();
ModifierSample modifierSample = new ModifierSample();
System.out.println(gson.toJson(modifierSample));
}
3.4、基于策略
GsonBuilder 类包含 setExclusionStrategies(ExclusionStrategy... strategies)
方法用于传入不定长参数的策略方法,用于直接排除指定字段名或者指定字段类型 看个例子
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class Strategies {
private String stringField;
private int intField;
private double doubleField;
public Strategies(String stringField, int intField, double doubleField) {
this.stringField = stringField;
this.intField = intField;
this.doubleField = doubleField;
}
@Override
public String toString() {
return “Strategies{” +
“stringField='” + stringField + ‘’’ +
“, intField=” + intField +
“, doubleField=” + doubleField +
‘}’;
}
}
public static void main(String[] args) {
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
//排除指定字段名
return fieldAttributes.getName().equals(“intField”);
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
//排除指定字段类型
return aClass.getName().equals(double.class.getName());
}
}).create();
Strategies strategies = new Strategies(“stringField”, 111, 11.22);
System.out.println();
System.out.println(gson.toJson(strategies));
String json = “{“stringField”:“stringField”,“intField”:111,“doubleField”:11.22}”;
strategies = gson.fromJson(json, Strategies.class);
System.out.println();
System.out.println(strategies);
}
字段名为 “intField” 和字段类型为 double 的字段都会被排除掉
setExclusionStrategies
方法在序列化和反序列化时都会生效,如果只是想指定其中一种情况下的排除策略或分别指定排除策略,可以改为使用以下两个方法
addSerializationExclusionStrategy(ExclusionStrategy strategy);
addDeserializationExclusionStrategy(ExclusionStrategy strategy);
四、个性化配置
4.1、输出 null
对于 Gson 而言,在序列化时如果某个属性值为 null 的话,那么在序列化时该字段不会参与进来,如果想要显示输出该字段的话,可以通过 GsonBuilder 进行配置
/**
- 作者:chenZY
- 时间:2018/3/17 18:32
- 描述:https://github.com/leavesC
*/
public class Strategies {
private String stringField;
private int intField;
private double doubleField;
}
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.serializeNulls() //输出null
.create();
Strategies strategies = new Strategies(null, 24, 22.333);
System.out.println();
System.out.println(gson.toJson(strategies));
}
4.2、格式化输出Json
默认的序列化后的 Josn 字符串并不太直观,可以选择格式化输出
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.serializeNulls() //输出null
.setPrettyPrinting()//格式化输出
.create();
Strategies strategies = new Strategies(null, 24, 22.333);
System.out.println();
System.out.println(gson.toJson(strategies));
}
4.3、格式化时间
Gson 也可以对时间值进行格式化
/**
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
时间
Gson 也可以对时间值进行格式化
/**
最后
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
[外链图片转存中…(img-PBZSjAe6-1714279342163)]
最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!