对于一些状态字段以前时兴用常量,现在时兴用枚举,虽然阅读体验极佳,但是传值的时候还是会有些麻烦,需要设置一下转换器.比如:

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对枚举的反序列化规则的更多相关文章

  1. @Convert 注解在jpa中进行查询的注意事项

    如果要实现实体类中属性的类型和数据库表中字段的类型相互转化,则需要使用 @Convert 注解 package javax.persistence; import java.lang.annotati ...

  2. @Data 注解引出的 lombok 小辣椒

    今天在看代码的时候, 看到了这个注解, 之前都没有见过, 所以就查了下, 发现还是个不错的注解, 可以让代码更加简洁. 这个注解来自于 lombok,lombok 能够减少大量的模板代码,减少了在使用 ...

  3. @Primary 注解引出的问题

    @Primary 注解 刚看到这个,还以为是持久层的注解呢,以为和@Id差不多,一查才知道,这两个风马牛不相及,反倒和@Qualifier以及@Resource有点像了,但是相比而言,后面两个更加的灵 ...

  4. Hibernate注解之@Enumerated:针对枚举enum(转)

    https://my.oschina.net/xinxingegeya/blog/359968 @Column(name = "store_type", nullable = fa ...

  5. [心得体会]springmvc在requestbody注解下使用jackson转化日期格式

    使用WebMvcConfigurer的方法将converter注入到项目中 @Configurationpublic class ConverterConfig implements WebMvcCo ...

  6. @Data 注解引出的 lombok

    今天在看代码的时候, 看到了这个注解, 之前都没有见过, 所以就查了下, 发现还是个不错的注解, 可以让代码更加简洁. 这个注解来自于 lombok,lombok 能够减少大量的模板代码,减少了在使用 ...

  7. 终极CRUD-3-用Jackson解析json

    目录 1 jackson json基本介绍和使用 2 jackson 常用的注解 2.1@JsonProperty 2.2 @JsonIgnore 2.3 @JsonIgnoreProperties ...

  8. java--加强之 jdk1.5简单新特性,枚举,注解

    转载请申明出处:http://blog.csdn.net/xmxkf/article/details/9944041 Jdk1.51新特性(静态导入,可变参数,加强for循环,自动拆装箱) 08.ja ...

  9. [Java] jackson注解

    Jackson(http://jackson.codehaus.org)库是基于java语言的开源json格式解析工具.相对于javajson解析的其他库,诸如json-lib.gson包,Jacks ...

随机推荐

  1. AjaxHandler

    概要 AjaxHandler组件是在ASP.NET MVC Web应用程序中实现ajax功能的一系列扩展方法,该组件的最初的实现方法借鉴了网上流行的部分源代码, ,经过博主不断完善和改进后推出的比较成 ...

  2. ArrayList的详解

    数组一旦给定大小就是固定的,只能放同类型的不能再改,还有一种高级的可扩充的,就是arrayList类,被称作动态数组或者集合. 使用步骤: 1. 引用命名空间system.collections: 2 ...

  3. git 先创建本地仓库,再关联远程

    之前都是先在GitHub或者bitbucket上创建repo,然后在本地直接git clone下来. 如果一定需要先在本地创建好文件夹,然后再关联远程仓库. 是这样: 1在远程创建仓库这步不变. 2 ...

  4. python+selenium2(一)

    一.安装python (1)在官网下载python的安装包,这里使用的是python3.5.安装一路下一步,安装路径我的是D:\Python35. (2)在计算机的path变量中添加D:\Python ...

  5. log4j动态监听配置修改

    一般情况下,log4j的配置文件是log4j.properties.但是每次我们修改了配置文件之后程序并不会自动去加载,而需要我们去重启程序.那么怎么样才能让程序不用重启就监听到变化呢.代码如下: p ...

  6. Python 编程快速上手 第十七章 操作图像

    前言 在这一章节,讲了关于图像的三个方面的内容: 获得图像的相关信息:例如 RGBA 值,尺寸... 对图像进行编辑操作:例如 旋转,缩放... 在图像上绘制形状:例如 矩形,圆形... [Image ...

  7. InitializingBean和DisposableBean

    InitializingBean 记住一点:InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的子类,在初始化bea ...

  8. hdu-4632 Palindrome subsequence (回文子序列计数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4632 问题要求回答一串字符串中回文子序列的数量,例如acbca就有 a,c,b,c,a,cc,aa,a ...

  9. 大div中嵌套小div,点击大div时隐藏,点击小div不隐藏

    给小div添加一个click事件 <div onClick="event.cancelBubble = true">  //小div

  10. mysql存储引擎的对比