GsonBuilder 初探
Gson 类提供的API满足我们大部分的使用场景,但是有时我们需要更强大的功能,这时候就需要使用 GsonBuilder。
GsonBuilder,见名知意,它用于构建Gson的实例,用来改变Gson的默认配置。
GsonBuilder 用法
1 | // 返回自定义的Gson实例。 |
我们来看一个示例:1
2
3
4
5public class User{
public String name;
public int age;
public String email;
}
1 | Gson gson = new Gson(); |
从结果可以看出email字段,在输出的json串中没有体现。如果我们需要通过日志输出查看User中所有的字段。1
2
3
4
5Gson gson = new GsonBuilder()
.serializeNulls()
.create();
User user = new User("Leo",28);
System.out.println(gson.toJson(user)); //{"name":"Leo","age":28,"email":null}
再来看一些高级点的功能,格式化输出,日期时间等1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json, 多了 )]}' 这4个字符)
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
.create();
字段过滤
在项目开发过程中,我们有些字段是不需要进行序列化的,那么在序列化时,我们就要将这些字段过滤,让我们来看一下 Gson 如何解决的这个问题,它提供四种方式:
基于 @Expose 注解
1 | (RetentionPolicy.RUNTIME) |
看源码注释,我们得知: @Expose 有两个属性 serialize 和 deserialize
,默认值为 true。
|属性|true|false|
|–|–|
|serialize|序列化|不序列化|
|deserialize|反序列化|不反序列化|
1 | public class User{ |
@Expose 注解必须配合 GsonBuilder 使用。1
2
3Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
基于版本 setVersion()
Gson 另外提供了两个注解 @Since 和 @Util ,配合setVersion(double version) 使用。当然我们还是通过代码来演示:
- 创建Gson实例 调用 setVersion(),设置版本为1.0
1
2
3Gson gson = new GsonBuilder()
.setVersion(1.0)
.create();
1 | public class User { |
@Since
当前版本大于或等于@Since标注版本时,字段可以序列化和反序列化。
上面代码 emailAddress 可以序列化和反序列化,address 不可以。@Util
当前版本小于@Util标注版本时,字段可以序列化和反序列化。
上面代码 username 可以序列化和反序列化,password 不可以。
注:当一个字段被 @Since 和 @Util 同时注解时,需两者同时满足条件。
基于访问修饰符
常用的修饰符 public、static、final、private、protected等等。
我们可以通过 excludeFieldsWithModifiers(int… modifiers)来过滤字段。1
2
3
4
5
6
7
8class ModifierSample {
final String finalField = "final";
static String staticField = "static";
public String publicField = "public";
protected String protectedField = "protected";
String defaultField = "default";
private String privateField = "private";
}
使用GsonBuilder.excludeFieldsWithModifiers构建gson,支持int形的可变参数,值由java.lang.reflect.Modifier提供,下面的程序排除了privateField 、 finalField 和staticField 三个字段。1
2
3Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
.create();
自定义规则
自定义规则相对麻烦一些,但是更强大,更灵活。
Gson提供了ExclusionStrategy接口,同样需要使用GsonBuilder,相关API 分别是addSerializationExclusionStrategy(序列化)和addDeserializationExclusionStrategy(反序列化)。下面我们以序列化为例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Gson 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();
序列化命名自定义
涉及到的API :
- GsonBuilder : setFieldNamingPolicy() 和 setFieldNamingStrategy()
- FieldNamingStrategy 接口
- 实现了FieldNamingStrategy 的枚举类 FieldNamingPolicy
Gson 提供的默认实现
setFieldNamingPolicy() 结合 FieldNamingPolicy1
2
3Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) .create();
Log.e("GsonDemo", gson.toJson(repository));
FieldNamingPolicy | 输出结果(emailAddress字段为例) |
---|---|
IDENTITY | {“emailAddress”:”leo@example.com“} |
LOWER_CASE_WITH_DASHES | {“email-address”:”leo@example.com“} |
LOWER_CASE_WITH_UNDERSCORES | {“email_address”:”leo@example.com“} |
UPPER_CAMEL_CASE | {“EmailAddress”:”leo@example.com“} |
UPPER_CAMEL_CASE_WITH_SPACES | {“Email Address”:”leo@example.com“} |
自定义规则
setFieldNamingStrategy() 结合 FieldNamingStrategy1
2
3
4
5
6
7
8
9Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
public String translateName(Field f) {
//实现自己的规则
return null;
}
})
.create();
注: @SerializedName 注解拥有最高优先级,在 @SerializedName 标注的字段上 FieldNamingStrategy 不生效!
随心所欲玩转序列化和反序列化
TypeAdapter
TypeAdapter
是Gson2.1提供的一个抽象类,用于POJO的序列化和反序列化。主要重写两个方法 write(JsonWriter out, T value) 和 read(JsonReader in)1
2
3
4public abstract class TypeAdapter<T> {
public abstract void write(JsonWriter out, T value) throws IOException;
public abstract T read(JsonReader in) throws IOException;
}
使用示例:1
2
3
4
5User user = new User("leo", 28,"leo@example.com");
Gson gson = new GsonBuilder()
//为User注册TypeAdapter
.registerTypeAdapter(User.class, new UserTypeAdapter())
.create();
1 | public class UserTypeAdapter extends TypeAdapter<User> { |
当我们为 User.class 注册了 TypeAdapter 之后,操作User.class的 那些@SerializedName、FieldNamingStrategy、@Since、@Until、@Expose,q全部废废,只会调用我们实现的UserTypeAdapter.write(JsonWriter, User) 方法,我们想怎么玩就怎么玩。
当然上面的序列化和反序列化的操作是有缺点的,如果我们想要对多个POJO随心所欲的操作,那么在创建 Gson 实例就要注册很多个 TypeAdapter ,追求代码洁癖的人会疯的。解决这个问题就需要用到 @JsonAdapter 注解。
@JsonAdapter
前面提到 @JsonAdapter 可以解决注册多个 TypeAdapter 的问题~ 它用来标注POJO类,接收一个参数,参数必须是 TypeAdapter,JsonSerializer或 JsonDeserializer 中的一个。
使用方法(以User为例):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15@JsonAdapter(UserTypeAdapter.class)
public class User{
public String name;
public int age;
@SerializedName(value="emialAddress")
public String email;
public User(){}
public User(String name,int age,String email){
this.name = name;
this.age = age;
this.email = email;
}
}
使用时不用再 GsonBuilder 去注册 UserTypeAdapter 了。
注:
- @JsonAdapter 仅支持 TypeAdapter 或 TypeAdapterFactory。
- @JsonAdapter 的优先级比 GsonBuilder.registerTypeAdapter 的优先级高。
JsonDeserializer 与 JsonSerializer
那么问题来了,我们只想控制序列化过程或者反序列化过程,比如我们后端经常在我们需要double类型数据时,返回空串””,导致我们数据异常,引起崩溃。肿么办?
同样见名知意, JsonDeserializer 可以用控制反序列化,JsonSerializer 控制序列化。
JsonDeserializer 反序列化操作
1 | Gson gson = new GsonBuilder() |
JsonSerializer
1 | JsonSerializer<Number> jsonSerializer = new JsonSerializer<Number>() { |
注: registerTypeAdapter
必须使用包装类型,所以 int.class ,long.class,double.class 是不可以的。
author: @ygwang