自定义fastjson对枚举类型的序列化及反序列化过程
通常,fastjson在序列化及反序列化枚举时,一般以下几种策略:
1).根据枚举的name值序列化及反序列化(默认)
2).根据枚举的ordinal序列化及反序列化
3).根据枚举的toString方法序列化,但是反序列仍采取默认的策略
这显然对我们的业务处理不够灵活,考虑以下一种情况:
有一个文章类,它有标题,内容等属性,其中有一个属性是枚举类,表示文章是否通过审核。
如下:
public class Article {private String title;
private String content;private AuditStatus status;public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}public AuditStatus getStatus() {
return status;
}
public void setStatus(AuditStatus status) {
this.status = status;
}
}
对应的枚举类型,它包含一个标志状态的code:
public enum AuditStatus {
AUDITING(1), PASSED(2), FAILED(3);
private int code;
AuditStatus(int code){
this.code = code;
}
public int getCode(){
return code;
}
public static AuditStatus convert(int code){
AuditStatus[] enums = AuditStatus.values();
for(AuditStatus e : enums){
if(e.code == code)
return e;
}
return null;
}
}
注意,上述的code并不等于枚举的ordinal。
我们希望AuditStatus序列化和反序列化的都是根据其code值来。
比如序列化成如下字符串:
{"content":"This is content","status":1,"title":"Article 1"}
并能正确反序列化得到的Article对象中的status属性是AuditStatus.AuditStatus。
我们逐个对应上述的策略来看看是否能满足我们的要求:
方法一:会将status序列化成AUDITING。因此不行
方法二:会将status根据ordinal来序列化,得到的结果为0,也不行。
方法三:我们可以override toString方法,这样可以是的序列化的结果正确,但是反序列化过程仍然不行。
那么没有其他方法可以满足我们的业务需求了嘛?
网上给出的一种方法如下,修改Article类:
public class Article {
private String title;
private String content;
private AuditStatus statusCode;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@JSONField(serialize = false)
public AuditStatus getStatusCode() {
return statusCode;
}
@JSONField(deserialize = true)
public void setStatusCode(AuditStatus statusCode) {
this.statusCode = statusCode;
}
@JSONField(name = "status")
public int getStatus(){
return statusCode.getCode();
}
@JSONField(name = "status")
public AuditStatus setStatus(int code){
return AuditStatus.convert(code);
}
}
这种方式屏蔽了默认的序列化及反序列化过程:行7(将status重命名成statusCode),行25-33(禁止了statusCode的序列化);并增加了自定义的序列化过程(行35-43)。
我测试了这种方式,虽然能在序列化时得到正常结果,但是却无法正常发序列化。
测试代码:
public class SerializeTest {
public static void main(String[] args){
Article article = new Article();
article.setTitle("Article 1");
article.setContent("This is content");
article.setStatusCode(AuditStatus.AUDITING);
String str = JSON.toJSONString(article);
System.out.println(str);
Article article1 = JSON.parseObject(str, Article.class);
System.out.println(article1.getStatusCode());
}
}
输出的结果:

因此这种做法并不可行,而且会让代码的可读性变差。
因此我推荐一种我尝试过成功的方法:编写自定义的编解码器,在通过@JsonField的serializeUsing和deserializeUsing属性指定编解码过程中使用的编解码器。
添加自定义的编解码器:
//ObjectSerializer和ObjectDeserializer分别是fastjson的编码器和解码器接口
public class AudtiStautsCodec implements ObjectSerializer, ObjectDeserializer {
//反序列化过程
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
Object value = parser.parse();
return value == null ? null : (T) AuditStatus.convert(TypeUtils.castToInt(value));
} //暂时还不清楚
public int getFastMatchToken() {
return 0;
} //序列化过程
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
serializer.write(((AuditStatus)object).getCode());
}
}
修改Article类,在status字段上增加@JsonField属性,并指定编解码器:
public class Article {
private String title;
private String content;
@JSONField(serializeUsing = AudtiStautsCodec.class, deserializeUsing = AudtiStautsCodec.class)
private AuditStatus status;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public AuditStatus getStatus() {
return status;
}
public void setStatus(AuditStatus status) {
this.status = status;
}
}
在通过之前的测试代码测试一下结果是否正确:
public class SerializeTest {
public static void main(String[] args){
Article article = new Article();
article.setTitle("Article 1");
article.setContent("This is content");
article.setStatus(AuditStatus.AUDITING);
String str = JSON.toJSONString(article);
System.out.println(str);
Article article1 = JSON.parseObject(str, Article.class);
System.out.println(article1.getStatus());
}
}
结果如下:

自定义fastjson对枚举类型的序列化及反序列化过程的更多相关文章
- 【json】与【枚举】的序列化和反序列化
参考:Jackson – Deserialization from json to Java enums 问题描述 java中使用枚举时,如果涉及到restful调用,不可避免会涉及到枚举的序列化和反 ...
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)
写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...
- 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题
原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...
- Java中Enum类型的序列化(转)
在Java中,对Enum类型的序列化与其他对象类型的序列化有所不同,今天就来看看到底有什么不同.下面先来看下在Java中,我们定义的Enum在被编译之后是长成什么样子的. Java代码: Java代码 ...
- 理解Java枚举类型
(参考资料:深入理解java enum) 1.原理:对编译后的class文件javap反编译可以看出,定义的枚举类继承自java.lang.Enum抽象类且通过public static final定 ...
- 用私有构造器或枚举类型强化Singleton
Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...
- Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解
Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全 Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...
- java 枚举类型分析
最近做android开发,需要用到枚举值,这样可以连续赋值,我按之前c++那样书写,如下所示: public enum ColorSelect { RED_BAGE = 0, GREEN_BAGE, ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
随机推荐
- jmeter执行多条sql语句
1.JDBC Connection Configuration 在配置DataBase URL的时候,加上allowMultiQueries=true 2.在JDBC Request中设置Quer T ...
- winform怎么实现财务上凭证录入和打印
序言 现如今存在的财务软件层出不穷,怎么样让自己的业务系统与财务系统相结合,往往是很多公司头痛的问题.大多数公司也没有这个能力都去开发一套属于自己的财务软件,所以只有对接像金蝶用友这类的财务软件,花费 ...
- python3(二十二) oop
""" 面向对象编程 """ __author__ = 'shaozhiqi' # 面向对象的程序设计把计算机程序视为一组对象的集合,而每个 ...
- win10+ubuntu双系统修复ubuntu启动引导
因为windows是不能引导linux的,而每次win10升级或恢复都会将linux的启动引导覆盖掉,导致无法进入linux, 所以一直就禁止了win10更新.这几天win10出了点小毛病,所以就狠下 ...
- windows 环境下dos 命令符下进D盘(非c盘系统盘)根目录
怎么进? 先 cd D: 然后 直接 D: 即可到D盘根目录,至于为啥要输入2遍D 才进D盘根目录,这就是windows的规定
- 数据结构和算法(Golang实现)(26)查找算法-哈希表
哈希表:散列查找 一.线性查找 我们要通过一个键key来查找相应的值value.有一种最简单的方式,就是将键值对存放在链表里,然后遍历链表来查找是否存在key,存在则更新键对应的值,不存在则将键值对链 ...
- vueCli 运行报错
error 如下: npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! shopping@0.1.0 serve: `vue-cli-service ...
- Three.js实现3D地图实例分享
本文主要给大家介绍了关于利用Three.js开发实现3D地图的实践过程,文中通过示例代码介绍的非常详细,对大家学习或者使用three.js具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习 ...
- OpenCV 之 基本绘图
OpenCV 虽是开源的计算机视觉库,但里面也有一些基础的绘图函数,本文将介绍几种常用绘图函数:直线.圆.椭圆.长方形.多边形等. 1 数据结构 1.1 二维向量 cv::Point 代表的是二维 ...
- eclipse添加方法注释
打开注释模板编辑窗口:Window ->Preferences->java -> Code Style -> Code Template->Comments type 设 ...