由@Convert注解引出的jackson对枚举的反序列化规则
对于一些状态字段以前时兴用常量,现在时兴用枚举,虽然阅读体验极佳,但是传值的时候还是会有些麻烦,需要设置一下转换器.比如:
class A{
@Convert(converter=TestTypeConverter.class)
private TestType test;
public TestType getTestType() {
return test;
}
public void setTestType(TestType test) {
this.test= test;
}
}
我们定义了如上一个类,其中的一个成员变量是枚举,为了能正常的接收前端的值,一般会给这个枚举定义个转换器来实现String到枚举的转换.但是呢同事发现不定义这个转换器依然可以接收前端的值,这引起了我的兴趣,所以打算一探究竟..
项目使用的Spring推荐的Jackson作为json的编解码,因为前后端都是用json传值,所以这个问题也就转化成Jackson究竟做了什么内部的优化能达到不定义转换器的情况下依然可以正确的反序列化枚举.然后我们看一下这个示例的枚举TestType:
public enum TestType {
ZERO(0,"0页"),
ONE(1,"1页"),
TWO(2,"2页");
@JsonCreator
public static IsAllType get(int value) {
try {
return map.get(value);
} catch (Exception e) {
return null;
}
}
private int value;
private String text;
IsAllType(int value, String text){
this.value=value;
this.text=text;
}
@JsonValue
public int getValue() {
return value;
}
}
示例,所以删减了部分无关代码.要debug跟踪,所以就通过json字符串转枚举这一过程来模拟前端传值这一操作,例子如下:
public static void main(String[] args) {
A a = JSONUtils.readValue("{\"test\": \"1\"}", A.class);
}
经过一顿debug发现,Jackson会优先使用@JsonCreator注解定义的方法进行构造枚举值,由于定义了构造方法,某种意义上这就是一个简易的枚举转换器.
到此那个不定义converter就能接收值的问题看似已经结束,但是我的好奇心是很旺盛的..我把这个@JsonCreator注解注释掉看看会怎么样?然后发现依然可以正常接收值..这就有点意思了..又是一顿debug发现如下关键代码
public static EnumResolver constructUsingMethod(Class<Enum<?>> enumCls,
Method accessor)
{
Enum<?>[] enumValues = enumCls.getEnumConstants();
HashMap<String, Enum<?>> map = new HashMap<String, Enum<?>>();
// from last to first, so that in case of duplicate values, first wins
for (int i = enumValues.length; --i >= 0; ) {
Enum<?> en = enumValues[i];
try {
Object o = accessor.invoke(en);
if (o != null) {
map.put(o.toString(), en);
}
} catch (Exception e) {
throw new IllegalArgumentException("Failed to access @JsonValue of Enum value "+en+": "+e.getMessage());
}
}
return new EnumResolver(enumCls, enumValues, map);
}
jackson会构造出一个map,这个map的key是枚举值的value值,value是枚举类中对应的枚举值,然后通过这个map依然可以实现值到枚举类的转换.那么何为枚举值的value值?
@JsonValue
public int getValue() {
return value;
}
jackson通过@JsonValue注解定义的方法返回值作为是枚举值的value值,通过这个value值又反向建立了关联,那我把这个@JsonValue注解也注释掉看看会怎么样?一运行发现还是可以接收值..
接着一顿debug发现如下关键代码:
public static EnumResolver constructUsingToString(Class<Enum<?>> enumCls)
{
Enum<?>[] enumValues = enumCls.getEnumConstants();
HashMap<String, Enum<?>> map = new HashMap<String, Enum<?>>();
// from last to first, so that in case of duplicate values, first wins
for (int i = enumValues.length; --i >= 0; ) {
Enum<?> e = enumValues[i];
map.put(e.toString(), e);
}
return new EnumResolver(enumCls, enumValues, map);
}
通过获取枚举类中所有的枚举值,然后它构建了一个map,只不过这个map的key有点特殊,是枚举值的ordinal值,value为枚举值,所以此时如果枚举值的value是从0开始,也就是恰巧和ordinal值重合时,这样转换不会有问题,否则则会大错特错..debug的途中发现一些好玩的开发者留言..
public static EnumResolver constructUnsafe(Class<?> rawEnumCls, AnnotationIntrospector ai)
{
/* This is oh so wrong... but at least ugliness is mostly hidden in just
* this one place.
*/
Class<Enum<?>> enumCls = (Class<Enum<?>>) rawEnumCls;
return constructFor(enumCls, ai);
} /**
* Method that needs to be used instead of {@link #constructUsingToString}
* if static type of enum is not known.
*/
@SuppressWarnings({ "unchecked" })
public static EnumResolver constructUnsafeUsingToString(Class<?> rawEnumCls)
{
// oh so wrong... not much that can be done tho
Class<Enum<?>> enumCls = (Class<Enum<?>>) rawEnumCls;
return constructUsingToString(enumCls);
} /**
* Method used when actual String serialization is indicated using @JsonValue
* on a method.
*/
@SuppressWarnings({ "unchecked" })
public static EnumResolver constructUnsafeUsingMethod(Class<?> rawEnumCls, Method accessor)
{
// wrong as ever but:
Class<Enum<?>> enumCls = (Class<Enum<?>>) rawEnumCls;
return constructUsingMethod(enumCls, accessor);
}
到此基本上我的好奇心也耗尽了...
总结: 1.jackson会优先使用@JsonCreator注解标注的构造方法构造枚举值
2.jackson会通过@JsonValue注解标注的方法作为value值构建value与枚举值的map映射
3.jackson会通过枚举值的ordinal值与枚举值构建map映射
ps:看来spring推荐jackson也并无道理,的确做了一些看不见的内部优化..
由@Convert注解引出的jackson对枚举的反序列化规则的更多相关文章
- @Convert 注解在jpa中进行查询的注意事项
如果要实现实体类中属性的类型和数据库表中字段的类型相互转化,则需要使用 @Convert 注解 package javax.persistence; import java.lang.annotati ...
- @Data 注解引出的 lombok 小辣椒
今天在看代码的时候, 看到了这个注解, 之前都没有见过, 所以就查了下, 发现还是个不错的注解, 可以让代码更加简洁. 这个注解来自于 lombok,lombok 能够减少大量的模板代码,减少了在使用 ...
- @Primary 注解引出的问题
@Primary 注解 刚看到这个,还以为是持久层的注解呢,以为和@Id差不多,一查才知道,这两个风马牛不相及,反倒和@Qualifier以及@Resource有点像了,但是相比而言,后面两个更加的灵 ...
- Hibernate注解之@Enumerated:针对枚举enum(转)
https://my.oschina.net/xinxingegeya/blog/359968 @Column(name = "store_type", nullable = fa ...
- [心得体会]springmvc在requestbody注解下使用jackson转化日期格式
使用WebMvcConfigurer的方法将converter注入到项目中 @Configurationpublic class ConverterConfig implements WebMvcCo ...
- @Data 注解引出的 lombok
今天在看代码的时候, 看到了这个注解, 之前都没有见过, 所以就查了下, 发现还是个不错的注解, 可以让代码更加简洁. 这个注解来自于 lombok,lombok 能够减少大量的模板代码,减少了在使用 ...
- 终极CRUD-3-用Jackson解析json
目录 1 jackson json基本介绍和使用 2 jackson 常用的注解 2.1@JsonProperty 2.2 @JsonIgnore 2.3 @JsonIgnoreProperties ...
- java--加强之 jdk1.5简单新特性,枚举,注解
转载请申明出处:http://blog.csdn.net/xmxkf/article/details/9944041 Jdk1.51新特性(静态导入,可变参数,加强for循环,自动拆装箱) 08.ja ...
- [Java] jackson注解
Jackson(http://jackson.codehaus.org)库是基于java语言的开源json格式解析工具.相对于javajson解析的其他库,诸如json-lib.gson包,Jacks ...
随机推荐
- Kali Linux 更新源 操作完整版教程
一.查看kali系统的更新源地址文件 命令: vim /etc/apt/sources.list 上面这是kali官方的更新源: 拓展知识: 一个完整的源包括:deb 和 deb-src:上图源地址是 ...
- HashMap源码解读
1.HashMap 1.6解读 a).put,get,遍历方式参看 http://www.cnblogs.com/skywang12345/p/3310835.html#a23 需要注意的是,1.7 ...
- Java——HashMap
获取数组长度 数组.length 获取下标 HashMap HashMap 构造函数 // 默认构造函数. HashMap() // 指定“容量大小”的构造函数 HashMap(int capacit ...
- List<String> list=new ArrayList<String>(20);为什么要声明为List 而不是ArrayList<String>?
如何理解:List<String> list=new ArrayList<String>();为甚麼要声明为List 而不是ArrayList<String>? 在 ...
- 力扣(LeetCode) 66. 加一
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: 输入 ...
- PostCSS以及cssnext语法
什么是postcss postcss 一种对css编译的工具,类似babel对js的处理,常见的功能如: 1 . 使用下一代css语法 2 . 自动补全浏览器前缀 3 . 自动把px代为转换成 rem ...
- ASA与N6K对接
ASA5545配置interface GigabitEthernet0/0 channel-group 10 mode active no nameif no security-level no ip ...
- ubuntu vi配置
1.先卸载tiny版本vi 输入命令:sudo apt-get remove vim-common 2.然后再输入命令: sudo apt-get install vim sudo vim /et ...
- win10系统同时安装python2和python3
1.官网下载python2和python3版本 2.安装python3,勾上Add Python3.5 to PATH,自定义选择安装目录,安装,验证:WIN+R--->cmd,输入python ...
- Spring Batch JSR-305 支持
本发布版本中为 JSR-305 支持添加了一个注解.这个为了与 Spring 框架中的 Null-safety 注解取得平衡,然后为 Spring Batch 添加为 public APIs. 这个 ...