这几天,因为项目的需要,接触了Google的Gson库,发现这个东西很好用,遂记下简单的笔记,供以后参考。至于Gson是干什么的,有什么优点,请各位同学自行百度。
1. 下载Gson
拷贝到项目的lib文件夹中,并将其加入到buildPath中。使用maven的同学,直接在pom中加入以下依赖即可:
1<dependency> 2 <groupId>com.google.code.gson</groupId> 3 <artifactId>gson</artifactId> 4 <version>2.2.4</version> 5</dependency>
2. 编写实体类
1public class People { 2 private String name; 3 private int age; 4 private boolean setName; 5 6 //ignored setter and getter 7 8 @Override 9 public String toString() { 10 return "name=" + name + " age=" + age + " setName=" + setName; 11 } 12}
3. 编写测试类
1public class GsonTest { 2 public static void main(String[] args) { 3 People p = new People(); 4 p.setAge(20); 5 p.setName("People"); 6 p.setSetName(true); 7 Gson gson = new Gson(); 8 System.out.println(gson.toJson(p)); 9 } 10}
输出结果:
{"name":"People","age":20,"setName":true}
4. 序列化部分字段
以上只是Gson的简单实用,如果我们需要将bool类型的属性setName在转换成json的时候不转换,怎么实现呢?
4.1 使用Java的transient关键字过滤
让字段不序列化的最简单的方式就是使用Java的关键字transient:
1public class People { 2 private String name; 3 private transient int age;//age is a transient field 4 private boolean setName; 5}
第3步测试类不变,则会有以下输出:
{"name":"People","setName":true}
4.2 使用Gson自带的Expose注解过滤
此注解作用在属性上,表明当序列化和反序列化的时候,这个属性将会暴露给Gson对象。这个注解只有当创建Gson对象时使用GsonBuilder方式创建并调用了GsonBuilder.excludeFieldsWithoutExposeAnnotation() 方法的时候才有效,否则无效。下面是一个介绍@Expose注解如何使用的例子:
1public class People { 2 @Expose 3 private String name; 4 @Expose(serialize = false, deserialize = false) 5 private int age; 6 private boolean setName; 7}
如果你以new Gson()的方式创建Gson对象,toJson()方法和fromJson() 方法在序列化和反序列化的时候将会操作这4个属性。然而,如果你使用
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
来创建Gson对象,Gson 的 toJson() 和 fromJson() 方法将会排除掉 setName 段,这是因为 setName 字段没有被注解 @Expose 所标记。 这个 Gson 对象同样会排除 age 字段,因为注解@Expose的属性 serialize 被设置成了 false。类似的,Gson也会在反序列化时排除掉 age 字段,因为 deserialize被设置成了 false。
第3步测试类只改变Gson对象的创建过程,则会有以下输出:
{"name":"People"}
4.3 使用Java修饰符过滤
先使用不同的修饰符来修饰字段,
1public class People { 2 private String name; 3 protected int age;//protected field 4 private boolean setName; 5}
然后在构造GsonBuilder的时候,可以使用以下方法,来过滤掉被指定修饰符修饰的字段:
Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PROTECTED).create();
输出:
{"name":"People","setName":true}
4.4 使用方法名过滤
在Gson的包中找半天,还发现com.google.gson包下面有这么一个接口:ExclusionStrategy ,根据名字可以推断,这个接口是用来设置Gson转换的排除策略的,于是在官网http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html查了一下这个接口,发现只要实现这个接口,并将实现类的对象塞给Gson,在转换成json的时候,Gson就会过滤掉指定的类或者属性。于是有了下面的代码:
1public class GsonTest { 2 public static void main(String[] args) { 3 People p = new People(); 4 p.setAge(20); 5 p.setName("People"); 6 p.setSetName(true); 7 ExclusionStrategy excludeStrategy = new SetterExclusionStrategy(); 8 Gson gson1 = new GsonBuilder() 9 .setExclusionStrategies(excludeStrategy) 10 .create(); 11 Gson gson2 = new Gson(); 12 String json1 = gson1.toJson(p); 13 String json2 = gson2.toJson(p); 14 System.out.println(json1); 15 System.out.println(json2); 16 17 People p1 = gson1.fromJson(json1, People.class); 18 People p2 = gson2.fromJson(json2, People.class); 19 System.out.println(p1); 20 System.out.println(p2); 21 } 22 23 private static class SetterExclusionStrategy implements ExclusionStrategy { 24 public boolean shouldSkipClass(Class<?> clazz) { 25 return false; 26 } 27 public boolean shouldSkipField(FieldAttributes f) { 28 return f.getName().startsWith("set"); 29 } 30 } 31}
原来,Gson对象的创建有两种方式:new Gson()表示使用默认的配置创建一个Gson对象,而如果使用GsonBuilder.create()方法创建,则可以自定义一些设置,这主要是为了使创建的Gson更适合于某些特定的情况。上例中第一段蓝色的代码创建了一个Gson对象,这个对象拥有对以“set”字样开头的属性的过滤的配置(如果需要过滤掉某种类型,则重写ExclusionStrategy接口的shouldSkipClass(Class<?> clazz)方法即可,如果需要过滤掉多种情况,则可以多创建几个ExclusionStrategy的实现类对象,并在创建Gson对象的时候设置进去即可),因此在本例中,将People对象转换成Json的时候,属性setName将被过滤掉。由于json1中没有属性setName,所以将json1反序列化成People对象的时候,boolean类型的setName就没有了值,所以打印的时候取了boolean类型的默认值。于是有了以下结果:
1{"name":"People","age":20} 2{"name":"People","age":20,"setName":true} 3name=People age=20 setName=false 4name=People age=20 setName=true
这个解决办法对方法的名称有要求,不是最佳解法。其实我们也可以使用自定义注解,这样的好处是不影响业务逻辑,也不影响方法命名。
4.5 使用自定义注解过滤
首先定义一个自定义的注解Exclude:
1import java.lang.annotation.ElementType; 2import java.lang.annotation.Retention; 3import java.lang.annotation.RetentionPolicy; 4import java.lang.annotation.Target; 5 6@Retention(RetentionPolicy.RUNTIME) 7@Target(ElementType.FIELD) 8public @interface Exclude { 9}
接下来将这个注解标注在指定的字段上:
1class People { 2 private String name; 3 @Exclude 4 private int age; 5 @Exclude 6 private boolean setName; 7}
修改测试类,和ExclusionStrategy类:
1public class GsonTest { 2 public static void main(String[] args) { 3 People p = new People(); 4 p.setAge(20); 5 p.setName("People"); 6 p.setSetName(true); 7 ExclusionStrategy excludeStrategy = new AnnotationExclusionStrategy(); 8 Gson gson1 = new GsonBuilder().setExclusionStrategies(excludeStrategy) 9 .create(); 10 Gson gson2 = new Gson(); 11 String json1 = gson1.toJson(p); 12 String json2 = gson2.toJson(p); 13 System.out.println(json1); 14 System.out.println(json2); 15 } 16 17 private static class AnnotationExclusionStrategy implements ExclusionStrategy { 18 public boolean shouldSkipClass(Class<?> clazz) { 19 return false; 20 } 21 22 public boolean shouldSkipField(FieldAttributes f) { 23 return f.getAnnotation(Exclude.class) != null; 24 } 25 } 26} 27
输出:
1{"name":"People"} 2{"name":"People","age":20,"setName":true}
5. 使用注解
在com.google.gson.annotation包中,有几个注解Expose, SerializedName, Since和Until,他们各有各的作用,下面使用官方例子介绍常用的注解:
5.1 SerializedName
此注解作用在属性上,表明这个属性在序列化成Json的时候,需要将名字序列化成注解的value属性指定的值。
这个注解将会覆盖任何的FieldNamingPolicy, 包括默认的命名策略。下面是一个介绍@SerializedName注解如何使用的例子:
1package com.my.gson; 2 3import com.google.gson.annotations.SerializedName; 4 5public class SomeClassWithFields { 6 @SerializedName("name") 7 private final String someField; 8 private final String someOtherField; 9 10 public SomeClassWithFields(String a, String b) { 11 this.someField = a; 12 this.someOtherField = b; 13 } 14}
下面的代码展示了序列化上面这个测试类的结果:
1SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b"); 2Gson gson = new Gson(); 3String jsonRepresentation = gson.toJson(objectToSerialize); 4System.out.println(jsonRepresentation);
执行结果是:
{"name":"a","someOtherField":"b"}
由此可见,属性"someField"已经被序列化成了"name"。
注意:在@SerializedName的value中指定的属性名必须为有效的Json属性名。
参考地址:
https://howtoprogram.xyz/2016/10/16/ignore-or-exclude-field-in-gson