Java json序列化库gson(2)
2017-07-05 00:00
351 查看
基于策略(自定义规则)
上面介绍的了3种排除字段的方法,说实话我除了@Expose以外,其它的都是只在Demo用上过,用得最多的就是马上要介绍的自定义规则,好处是功能强大、灵活,缺点是相比其它3种方法稍麻烦一点,但也仅仅只是想对其它3种稍麻烦一点而已。
基于策略是利用Gson提供的
默认实现
自定义实现
用法:
注意:
注意:TypeAdapter 以及 JsonSerializer 和 JsonDeserializer 都需要与
UserTypeAdapter的定义:
当我们为
再说一个场景,在该系列的第一篇文章就说到了Gson有一定的容错机制,比如将字符串
int型会出错是吧,根据我们上面介绍的,我注册一个TypeAdapter 把 序列化和反序列化的过程接管不就行了?
注:测试空串的时候一定是
你说这一接管就要管两样好麻烦呀,我明明只想管序列化(或反列化)的过程的,另一个过程我并不关心,难道没有其它更简单的方法么? 当然有!就是接下来要介绍的 JsonSerializer与JsonDeserializer。
下面是所有数字都转成序列化为字符串的例子
registerTypeAdapter与registerTypeHierarchyAdapter的区别:
注:如果一个被序列化的对象本身就带有泛型,且注册了相应的
上面说
使用方法(以User为例):
使用时不用再使用
注:
上面介绍的了3种排除字段的方法,说实话我除了@Expose以外,其它的都是只在Demo用上过,用得最多的就是马上要介绍的自定义规则,好处是功能强大、灵活,缺点是相比其它3种方法稍麻烦一点,但也仅仅只是想对其它3种稍麻烦一点而已。
基于策略是利用Gson提供的
ExclusionStrategy接口,同样需要使用
GsonBuilder,相关API 2个,分别是
addSerializationExclusionStrategy和
addDeserializationExclusionStrategy分别针对序列化和反序化时。这里以序列化为例。
Gson 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();
二、 POJO与JSON的字段映射规则
还是之前User的例子,已经去除所有注解:User user = new User("怪盗kidou", 24); user.emailAddress = "ikidou@example.com";
GsonBuilder提供了
FieldNamingStrategy接口和
setFieldNamingPolicy和
setFieldNamingStrategy两个方法。
默认实现
GsonBuilder.setFieldNamingPolicy方法与Gson提供的另一个枚举类
FieldNamingPolicy配合使用,该枚举类提供了5种实现方式分别为:
FieldNamingPolicy | 结果(仅输出emailAddress字段) |
---|---|
IDENTITY | {"emailAddress":"ikidou@example.com"} |
LOWER_CASE_WITH_DASHES | {"email-address":"ikidou@example.com"} |
LOWER_CASE_WITH_UNDERSCORES | {"email_address":"ikidou@example.com"} |
UPPER_CAMEL_CASE | {"EmailAddress":"ikidou@example.com"} |
UPPER_CAMEL_CASE_WITH_SPACES | {"Email Address":"ikidou@example.com"} |
GsonBuilder.setFieldNamingStrategy方法需要与Gson提供的
FieldNamingStrategy接口配合使用,用于实现将POJO的字段与JSON的字段相对应。上面的
FieldNamingPolicy实际上也实现了
FieldNamingStrategy接口,也就是说
FieldNamingPolicy也可以使用
setFieldNamingStrategy方法。
用法:
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new FieldNamingStrategy() { @Override public String translateName(Field f) { //实现自己的规则 return null; } }) .create();
注意:
@SerializedName注解拥有最高优先级,在加有
@SerializedName注解的字段上
FieldNamingStrategy不生效!
一、TypeAdapter
TypeAdapter是Gson自2.0(源码注释上说的是2.1)开始版本提供的一个抽象类,用于接管某种类型的序列化和反序列化过程,包含两个注要方法
write(JsonWriter,T)和
read(JsonReader)其它的方法都是
final方法并最终调用这两个抽象方法。
public abstract class TypeAdapter<T> { public abstract void write(JsonWriter out, T value) throws IOException; public abstract T read(JsonReader in) throws IOException; //其它final 方法就不贴出来了,包括`toJson`、`toJsonTree`、`toJson`和`nullSafe`方法。 }
注意:TypeAdapter 以及 JsonSerializer 和 JsonDeserializer 都需要与
GsonBuilder.registerTypeAdapter示或
GsonBuilder.registerTypeHierarchyAdapter配合使用,下面将不再重复说明。实例如下:
User user = new User("怪盗kidou", 24); user.emailAddress = "ikidou@example.com";
Gson gson = new GsonBuilder()
//为User注册TypeAdapter
.registerTypeAdapter(User.class, new UserTypeAdapter())
.create();
System.out.println(gson.toJson(user));
UserTypeAdapter的定义:
public class UserTypeAdapter extends TypeAdapter<User> { @Override public void write(JsonWriter out, User value) throws IOException { out.beginObject(); out.name("name").value(value.name); out.name("age").value(value.age); out.name("email").value(value.email); out.endObject(); } @Override public User read(JsonReader in) throws IOException { User user = new User(); in.beginObject(); while (in.hasNext()) { switch (in.nextName()) { case "name": user.name = in.nextString(); break; case "age": user.age = in.nextInt(); break; case "email": case "email_address": case "emailAddress": user.email = in.nextString(); break; } } in.endObject(); return user; } }
当我们为
User.class注册了
TypeAdapter之后,只要是操作
User.class那些之前介绍的
@SerializedName、
FieldNamingStrategy、
Since、
Until、
Expos通通都黯然失色,失去了效果,只会调用我们实现的
UserTypeAdapter.write(JsonWriter, User)方法,我想怎么写就怎么写。
再说一个场景,在该系列的第一篇文章就说到了Gson有一定的容错机制,比如将字符串
"24"转成int 的
24,但如果有些情况下给你返了个空字符串怎么办(有人给我评论问到这个问题)?虽然这是服务器端的问题,但这里我们只是做一个示范。
int型会出错是吧,根据我们上面介绍的,我注册一个TypeAdapter 把 序列化和反序列化的过程接管不就行了?
Gson gson = new GsonBuilder() .registerTypeAdapter(Integer.class, new TypeAdapter<Integer>() { @Override public void write(JsonWriter out, Integer value) throws IOException { out.value(String.valueOf(value)); } @Override public Integer read(JsonReader in) throws IOException { try { return Integer.parseInt(in.nextString()); } catch (NumberFormatException e) { return -1; } } }) .create(); System.out.println(gson.toJson(100)); // 结果:"100" System.out.println(gson.fromJson("\"\"",Integer.class)); // 结果:-1
注:测试空串的时候一定是
"\"\""而不是
"",
""代表的是没有json串,
"\"\""才代表json里的
""。
你说这一接管就要管两样好麻烦呀,我明明只想管序列化(或反列化)的过程的,另一个过程我并不关心,难道没有其它更简单的方法么? 当然有!就是接下来要介绍的 JsonSerializer与JsonDeserializer。
二、JsonSerializer与JsonDeserializer
JsonSerializer和
JsonDeserializer不用像
TypeAdapter一样,必须要实现序列化和反序列化的过程,你可以据需要选择,如只接管序列化的过程就用
JsonSerializer,只接管反序列化的过程就用
JsonDeserializer,如上面的需求可以用下面的代码。
Gson gson = new GsonBuilder() .registerTypeAdapter(Integer.class, new JsonDeserializer<Integer>() { @Override public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsInt(); } catch (NumberFormatException e) { return -1; } } }) .create(); System.out.println(gson.toJson(100)); //结果:100 System.out.println(gson.fromJson("\"\"", Integer.class)); //结果-1
下面是所有数字都转成序列化为字符串的例子
JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() { @Override public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(String.valueOf(src)); } }; Gson gson = new GsonBuilder() .registerTypeAdapter(Integer.class, numberJsonSerializer) .registerTypeAdapter(Long.class, numberJsonSerializer) .registerTypeAdapter(Float.class, numberJsonSerializer) .registerTypeAdapter(Double.class, numberJsonSerializer) .create(); System.out.println(gson.toJson(100.0f));//结果:"100.0"
registerTypeAdapter与registerTypeHierarchyAdapter的区别:
registerTypeAdapter | registerTypeHierarchyAdapter | |
---|---|---|
支持泛型 | 是 | 否 |
支持继承 | 否 | 是 |
TypeAdapter,那么必须调用
Gson.toJson(Object,Type),明确告诉Gson对象的类型。
Type type = new TypeToken<List<User>>() {}.getType(); TypeAdapter typeAdapter = new TypeAdapter<List<User>>() { //略 }; Gson gson = new GsonBuilder() .registerTypeAdapter(type, typeAdapter) .create(); List<User> list = new ArrayList<>(); list.add(new User("a",11)); list.add(new User("b",22)); //注意,多了个type参数 String result = gson.toJson(list, type);
三、TypeAdapterFactory
TypeAdapterFactory,见名知意,用于创建TypeAdapter的工厂类,通过对比Type,确定有没有对应的
TypeAdapter,没有就返回null,与
GsonBuilder.registerTypeAdapterFactory配合使用。
Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new TypeAdapterFactory() { @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { return null; } }) .create();
四、@JsonAdapter注解
JsonAdapter相较之前介绍的
SerializedName、
FieldNamingStrategy、
Since、
Until、
Expos这几个注解都是比较特殊的,其它的几个都是用在POJO的字段上,而这一个是用在POJO类上的,接收一个参数,且必须是
TypeAdpater,
JsonSerializer或
JsonDeserializer这三个其中之一。
上面说
JsonSerializer和
JsonDeserializer都要配合
GsonBuilder.registerTypeAdapter使用,但每次使用都要注册也太麻烦了,
JsonAdapter就是为了解决这个痛点的。
使用方法(以User为例):
@JsonAdapter(UserTypeAdapter.class) //加在类上 public class User { public User() { } public User(String name, int age) { this.name = name; this.age = age; } public User(String name, int age, String email) { this.name = name; this.age = age; this.email = email; } public String name; public int age; @SerializedName(value = "emailAddress") public String email; }
使用时不用再使用
GsonBuilder去注册
UserTypeAdapter了。
注:
@JsonAdapter仅支持
TypeAdapter或
TypeAdapterFactory
Gson gson = new Gson(); User user = new User("怪盗kidou", 24, "ikidou@example.com"); System.out.println(gson.toJson(user)); //结果:{"name":"怪盗kidou","age":24,"email":"ikidou@example.com"} //为区别结果,特意把email字段与@SerializedName注解中设置的不一样
五、TypeAdapter与 JsonSerializer、JsonDeserializer对比
TypeAdapter | JsonSerializer、JsonDeserializer | |
---|---|---|
引入版本 | 2.0 | 1.x |
Stream API | 支持 | 不支持*,需要提前生成JsonElement |
内存占用 | 小 | 比TypeAdapter大 |
效率 | 高 | 比TypeAdapter低 |
作用范围 | 序列化 和 反序列化 | 序列化 或 反序列化 |
相关文章推荐
- Java json序列化库gson.
- GSON实现Java对象的JSON序列化与反序列化的实例教程
- java序列化框架(protobuf、thrift、kryo、fst、fastjson、Jackson、gson、hessian)性能对比
- Gson教程一(译):Java-JSON的序列化和反序列化
- Gson - Java-JSON 序列化和反序列化入门
- Gson - Java-JSON 序列化和反序列化入门
- 使用Gson反序列化Json数据失败,报错JsonSyntaxException: java.lang.IllegalStateException
- Mvc4 web-Api Json 序列化,日期Java解析失败的解决方法
- 使用Gson将Java对象转换为Json
- gson(JSON字符串转换成一个相等的Java对象)
- How to convert Java object to / from JSON (Gson)
- Java中Json的序列化和反序列化
- java json序列化自定义类,类数组
- Java gson使用 将Java对象转为Json 并 Json转回Java对象
- 很好用的Google 开源项目Gson在java中解析和创建json格式的数据
- 使用Gson将Java对象转换为Json
- Gson对Java嵌套对象和JSON字符串之间的转换
- JAVA序列化与反序列化三种格式存取(默认格式、XML格式、JSON格式)
- Java Json/xml 序列化和反序列化 工具:JsonTools 和 simpleframework 附带实例
- Java Json/xml 序列化和反序列化工具:JsonTools 和 simpleframework【附带实例】