- 1. 项目依赖
- 2. 基本使用姿势
- 3. 泛型反序列化
- 4. 转Map/List
- 5. JsonNode
- 6. 驼峰与下划线
- 7. 字段别名
- 8. 字段忽略
- 9. Java Bean约定
- 10. Json串存在Bean未定义字段忽略设置
- 11. 序列化输出时忽略null
- 12. key为null场景兼容
- 13 其他
使用json进行数据交互可以说是非常常见的常见,在java侧,常用的json解析框架也不少,比如gson, fastjson以及spring mvc中默认使用的jackson;本文将主要介绍一下jackson的基本使用姿势,比如常见的
- 普通对象转json字符串
- json字符串转POJO,转Map/List
- 泛型支持
- 驼峰/下划线互转,自定义映射关系
1. 项目依赖
使用maven来构建项目,需要使用Jackson进行序列化操作,核心引入下面的包
1 | <dependency> |
2. 基本使用姿势
在Jackson中,若希望实现序列化/反序列化,都离不开ObjectMapper
比如将对象转Json String
1 | public static <T> String encode(T obj) { |
反序列化
1 | public static <T> T decode(String str, Class<T> clz) { |
注意
- jackson与gson/fastjson的一个显著区别在于它的序列化/反序列化有声明异常,使用时需要声明或者主动catch(这一点感觉不太友好)
- 其次,不推荐每次都创建一个ObjectMapper对象,可以考虑复用
3. 泛型反序列化
对于泛型的反序列化,直接使用上面,传入一个class对象,并不能很好的工作,和Gson/FastJson一样,Jackson也支持根据Type来返序列化
1 | public static <T> T decode(String str, Type type) { |
重点关注上面的传参,通过objectMapper.getTypeFactory().constructType(type)
来创建需要的JavaType对象
一个demo使用姿势如下
1 | GenericBean<Map> gbean2 = JacksonUtil.decode(str, new com.fasterxml.jackson.core.type |
4. 转Map/List
转普通的Map/List没有什么特殊的
1 | public static Map toMap(String str) { |
5. JsonNode
JsonNode为Jackson定义的节点对象,有些类似Gson的JsonObject/JsonArray
和 FastJson的JSONObject/JSONArray
,使用它可以更友好的操作json对象(当然更推荐的是直接转JAVA bean)
1 | public static JsonNode toObj(String str) { |
使用demo如下
1 | String str = "{\"userId\":12,\"userName\":\"yh\",\"userMoney\":12.3,\"userSkills\":[\"1\",\"2\",\"3\"],\"extra\":{\"a\":\"123\",\"b\":345,\"c\":[\"1\",\"2\",\"3\"],\"d\":35.1},\"hello\":\"你好\"}"; |
6. 驼峰与下划线
常见的一个case,json字符串key为下划线,Java bean为驼峰命名,针对这种场景,jackson可以很方便的支持
1 | /** |
从上面的代码也可以看出,驼峰与下划线的互转支持,主要是通过设置PropertyNamingStrategies
来实现的,在jackson中,支持下面几种配置
LOWER_CAMEL_CASE
UPPER_CAMEL_CASE
SNAKE_CASE
LOWER_CASE
KEBAB_CASE
LOWER_DOT_CASE
使用上面这种方式适用于全局的下划线与驼峰的转换方式,如果我只希望针对单独某个类进行这样的设置呢?
可以借助注解@JsonNaming
来实现
1 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) |
上面这个case中,如果我们将SimpleBean对象序列化为json串,即便调用的是前面最基础的使用姿势 new ObjectMapper().writeValueAsString(simpleBean)
,输出的也是下划线格式的json串;同理反序列化时,也是将下划线转为驼峰
7. 字段别名
上面介绍的是驼峰与下划线命名方式,当然也会有一些其他特殊的场景,针对某个字段进行别名设置,可以通过注解@JsonProperties
来标注
1 | @JsonProperty("user") |
上面这个表示序列化为json字符串时,userName对应的key为user
8. 字段忽略
在序列化时,难免会遇到某些字段不进行序列化/反序列化的场景,这里有两种常用的方式
8.1 @JsonIgnore注解
直接在希望忽略的字段上添加注解@JsonIgnore
即可,如
1 | @Data |
8.2 transient关键字
除了使用上面的注解之外,也可以使用jdk原生提供的关键字transient
来声明需要忽略的字段
1 | private transient SimpleBean self; |
重点注意:
- 在jackson中,默认的场景下,即便字段上修饰有
transient
关键字,也不会忽略还需要如下处理
1 | objectMapper = new ObjectMapper(); |
上面两种方式,都可以实现忽略transient
关键字修饰的对象序列化
9. Java Bean约定
9.1 get/set方法必须有
Java Bean的get/set方法必须存在,否则额序列化与反序列化只会处理public修饰的成员
1 | public class SimpleBean { |
序列化后输出为 {"desc":"hello world"}
; 反序列化也不会更新 name
, userId
;
特别的,当Java Bean对象,所有的成员都是private,又没有get方法时,在序列化时,会抛异常,提示信息如下
1 | No serializer found for class com.git.hui.spring.json.bean.SimpleBean and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) |
9.2 无参构造函数必须有
如果java bean没有默认无参构造方法,那么在反序列化时,会抛出异常,无法实例化
一个如下的异常提示信息
1 | Cannot construct instance of `com.git.hui.spring.json.bean.SimpleBean` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) |
10. Json串存在Bean未定义字段忽略设置
默认的使用姿势下,若json串中存在一个bean未定义的kv,会抛异常,一个示例如下
1 | Unrecognized field "xxx" (class com.git.hui.spring.json.bean.GenericBean), not marked as ignorable |
如果希望忽略这种场景,那么就需要禁用FAIL_ON_UNKNOWN_PROPERTIES
配置
1 | new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) |
扩展知识点
- 对于Spring MVC而言,默认使用的是Jackson序列化框架,如果我们定义接收参数为json串,那么当前端传参多了一个未定义的字段,会直接抛异常么?
11. 序列化输出时忽略null
默认场景下,将一个bean对象序列化为json串,即便成员变量为null,也会输出,如下
1 | { |
这种case某些场景下是合适的,比如生成接口文档示例时,更关心的是参数说明,即便为null,也是希望有这个;但是另外一些场景下则希望忽略,毕竟可以节省对象大小
需要忽略null字段时,可以如下设置
1 | new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL) |
关键点就是配置 setSerializationInclusion(JsonInclude.Include.NON_NULL)
12. key为null场景兼容
对于普通的Java bean而言,不存在key为null的场景,但是如果是将一个Map对象,输出为json串时,那么就可能出现这种场景了,如
1 | Map<String, String> map = new HashMap<>(); |
上面这个执行,直接抛异常
1 | Null key for a Map not allowed in JSON (use a converting NullKeySerializer?) |
如果希望兼容这个场景,则可以如下处理
1 | ObjectMapper objectMapper = new ObjectMapper(); |
上面这个做法,就是将key为null的,以null
字符串来替代
说明
- 既然key可能为null,当然也为其他类型,但是在序列化输出时,会转String
如下面这个case
1 | Map map = new HashMap(); |
输出的字符串为
1 | {"[]":123} |
13 其他
以上的知识点,基本上可以覆盖我们日常在使用Jackson进行序列化和反序列化中95%的场景,至于其他的比如自定义Name策略,反序列化的默认值类型,类型转换,json注释的支持与否等相对少见的姿势,看后续是否有空补上
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
微信公众号:一灰灰blog