Java json序列化库gson(2)
2019独角兽企业重金招聘Python工程师标准>>>
基于策略(自定义规则)
上面介绍的了3种排除字段的方法,说实话我除了@Expose以外,其它的都是只在Demo用上过,用得最多的就是马上要介绍的自定义规则,好处是功能强大、灵活,缺点是相比其它3种方法稍麻烦一点,但也仅仅只是想对其它3种稍麻烦一点而已。
基于策略是利用Gson提供的ExclusionStrategy
接口,同样需要使用GsonBuilder
,相关API 2个,分别是addSerializationExclusionStrategy
和addDeserializationExclusionStrategy
分别针对序列化和反序化时。这里以序列化为例。
Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {@Overridepublic 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;}@Overridepublic 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() {@Overridepublic 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> {@Overridepublic 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();}@Overridepublic 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>() {@Overridepublic void write(JsonWriter out, Integer value) throws IOException {out.value(String.valueOf(value)); }@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic 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() {@Overridepublic <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 低
|
作用范围 | 序列化 和 反序列化 | 序列化 或 反序列化 |
转载于:https://my.oschina.net/hutaishi/blog/1162303
Java json序列化库gson(2)相关推荐
- 黑马程序员python笔记_#华为云·寻找黑马程序员# 如何实现一个优雅的Python的Json序列化库...
[小宅按]在Python的世界里,将一个对象以json格式进行序列化或反序列化一直是一个问题.Python标准库里面提供了json序列化的工具,我们可以简单的用json.dumps来将一个对象序列化. ...
- #华为云·寻找黑马程序员# 如何实现一个优雅的Python的Json序列化库
在Python的世界里,将一个对象以json格式进行序列化或反序列化一直是一个问题.Python标准库里面提供了json序列化的工具,我们可以简单的用json.dumps来将一个对象序列化.但是这种序 ...
- json支持的最大长度_Swifter.Json 可能是 .Net 平台迄今为止性能最佳的 Json 序列化库【开源】...
Json 简介 Json (JavaScript Object Notation) 是一种轻量级的数据交换格式.它作为目前最欢迎的数据交换格式,也是各大开源贡献者的必争之地,如:阿里爸爸的 fast ...
- Newtonsoft.Json序列化库
Unity自己的Json序列化是不支持字典格式的,而且功能比较单一,这里介绍一个.Net中开源的Json序列化和反序列化库和基本用法以及常用的数据处理方法(github地址:https://githu ...
- JAVA——json序列化错误[hibernateLazyInitializer,handler,fieldHandler]解决方案
问题描述 (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain ...
- Android学习之Json解析库Gson
接着上一篇Volley,在使用Volley加载好数据之后,我们肯定不能直接使用这个数据,一般获取的数据都会是Json格式,所以自然而然我们要处理下Json,网络上有很多Json解析库,这里我使用Gso ...
- Java Json API:Gson使用简单入门
GSON是Google开发的Java API,用于转换Java对象和Json对象.本文讨论并提供了使用API的简单代码示例.更多关于GSON的API可以访问:http://sites.google.c ...
- java json 序列化对象空值不处理_jackson 实体转json 为NULL或者为空不参加序列化(实例讲解)...
使用jackson进行序列化时,往往会遇到后台某个实体对象的属性为null,当序列化成json时对应的属性也为null:这样在某些前端组件上应用该json对象会报错.(例如:echarts) 下面总结 ...
- Java中的Json序列化,不容忽视的getter
文章目录 前言 一.Java中的Json序列化,不容忽视的getter 二.问题重现 1.核心代码 2.问题分析 2.1常用 JSON序列化库 的序列化原理: 总结 前言 提示:这里可以添加本文要记录 ...
最新文章
- 浅议 JavaScript 的 Promises/Futures 模式
- Win32 汇编语句模板
- Python中按指定长度分割字符串并反转
- 取消mysql自动备份文件_MySQL自动备份并清理多少天前的备份文件
- jqueryonclick事件_jquery动态移除/增加onclick属性详解
- springcloud服务发现
- Unity3D的LightProbe动态光探头用法介绍
- OpenWRT in VirtualBox
- 伪随机数与采样(sampling)
- WinForm timer 控件
- c语言gcno文件位置,c – 找不到CMake和lcov:gcno文件
- Hadoop安装详细教程 单机版
- sql 常见查询代码操作
- Notepad++--常用的插件
- 解决Python中的TypeError list indices must be integers or slices, not float问题
- 二叉树层次遍历(自下而上)
- win10计算机怎么打开方式,Win10如何还原打开方式?还原打开方式的方法
- 炉石传说游戏系统拆解
- ESP-8266接入阿里云开关LED
- schedule_delayed_work()
热门文章
- java jvm容器_java – YARN:容器和JVM
- mysql 阿里云 优化_MySQL性能优化速记
- oracle json入参调用ws服务返回请求失败_Spring 5.2.2技术集成 —Spring HTTP调用程序和JAXWS...
- python插入排序_从Python看排序:插入排序
- 01Struts 2
- 各项兼容坑的记录-持续更新
- 重操JS旧业第十一弹:BOM对象
- 外挂安装eclipse插件
- 无任何网络提供程序接受指定的网络路径 or No network provider accepted the given network path 的解决方法...
- 自动化设备的软件框架