通常,fastjson在序列化及反序列化枚举时,一般以下几种策略:

1).根据枚举的name值序列化及反序列化(默认)

2).根据枚举的ordinal序列化及反序列化

3).根据枚举的toString方法序列化,但是反序列仍采取默认的策略

这显然对我们的业务处理不够灵活,考虑以下一种情况:

有一个文章类,它有标题,内容等属性,其中有一个属性是枚举类,表示文章是否通过审核。

如下:

  1. public class Article {private String title;
  2.  
  3. private String content;private AuditStatus status;public String getTitle() {
  4. return title;
  5. }
  6.  
  7. public void setTitle(String title) {
  8. this.title = title;
  9. }
  10.  
  11. public String getContent() {
  12. return content;
  13. }
  14.  
  15. public void setContent(String content) {
  16. this.content = content;
  17. }public AuditStatus getStatus() {
  18. return status;
  19. }
  20.  
  21. public void setStatus(AuditStatus status) {
  22. this.status = status;
  23. }
  24. }

对应的枚举类型,它包含一个标志状态的code:

  1. public enum AuditStatus {
  2. AUDITING(1), PASSED(2), FAILED(3);
  3.  
  4. private int code;
  5.  
  6. AuditStatus(int code){
  7. this.code = code;
  8. }
  9.  
  10. public int getCode(){
  11. return code;
  12. }
  13. public static AuditStatus convert(int code){
  14. AuditStatus[] enums = AuditStatus.values();
  15. for(AuditStatus e : enums){
  16. if(e.code == code)
  17. return e;
  18. }
  19. return null;
  20. }
  21. }

注意,上述的code并不等于枚举的ordinal。

我们希望AuditStatus序列化和反序列化的都是根据其code值来。

比如序列化成如下字符串:

  1. {"content":"This is content","status":1,"title":"Article 1"}

并能正确反序列化得到的Article对象中的status属性是AuditStatus.AuditStatus。

我们逐个对应上述的策略来看看是否能满足我们的要求:

方法一:会将status序列化成AUDITING。因此不行

方法二:会将status根据ordinal来序列化,得到的结果为0,也不行。

方法三:我们可以override toString方法,这样可以是的序列化的结果正确,但是反序列化过程仍然不行。

那么没有其他方法可以满足我们的业务需求了嘛?

网上给出的一种方法如下,修改Article类:

  1. public class Article {
  2.  
  3. private String title;
  4.  
  5. private String content;
  6.  
  7. private AuditStatus statusCode;
  8.  
  9. public String getTitle() {
  10. return title;
  11. }
  12.  
  13. public void setTitle(String title) {
  14. this.title = title;
  15. }
  16.  
  17. public String getContent() {
  18. return content;
  19. }
  20.  
  21. public void setContent(String content) {
  22. this.content = content;
  23. }
  24.  
  25. @JSONField(serialize = false)
  26. public AuditStatus getStatusCode() {
  27. return statusCode;
  28. }
  29.  
  30. @JSONField(deserialize = true)
  31. public void setStatusCode(AuditStatus statusCode) {
  32. this.statusCode = statusCode;
  33. }
  34.  
  35. @JSONField(name = "status")
  36. public int getStatus(){
  37. return statusCode.getCode();
  38. }
  39.  
  40. @JSONField(name = "status")
  41. public AuditStatus setStatus(int code){
  42. return AuditStatus.convert(code);
  43. }
  44. }

这种方式屏蔽了默认的序列化及反序列化过程:行7(将status重命名成statusCode),行25-33(禁止了statusCode的序列化);并增加了自定义的序列化过程(行35-43)。

我测试了这种方式,虽然能在序列化时得到正常结果,但是却无法正常发序列化。

测试代码:

  1. public class SerializeTest {
  2. public static void main(String[] args){
  3. Article article = new Article();
  4. article.setTitle("Article 1");
  5. article.setContent("This is content");
  6. article.setStatusCode(AuditStatus.AUDITING);
  7.  
  8. String str = JSON.toJSONString(article);
  9. System.out.println(str);
  10.  
  11. Article article1 = JSON.parseObject(str, Article.class);
  12. System.out.println(article1.getStatusCode());
  13. }
  14. }

输出的结果:

因此这种做法并不可行,而且会让代码的可读性变差。

因此我推荐一种我尝试过成功的方法:编写自定义的编解码器,在通过@JsonField的serializeUsing和deserializeUsing属性指定编解码过程中使用的编解码器。

添加自定义的编解码器:

  1. //ObjectSerializer和ObjectDeserializer分别是fastjson的编码器和解码器接口
  2. public class AudtiStautsCodec implements ObjectSerializer, ObjectDeserializer {
  3. //反序列化过程
  4. public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
  5. Object value = parser.parse();
  6. return value == null ? null : (T) AuditStatus.convert(TypeUtils.castToInt(value));
  7. }
  8.  
  9. //暂时还不清楚
  10. public int getFastMatchToken() {
  11. return 0;
  12. }
  13.  
  14. //序列化过程
  15. public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
  16. serializer.write(((AuditStatus)object).getCode());
  17. }
  18. }

修改Article类,在status字段上增加@JsonField属性,并指定编解码器:

  1. public class Article {
  2.  
  3. private String title;
  4.  
  5. private String content;
  6.  
  7. @JSONField(serializeUsing = AudtiStautsCodec.class, deserializeUsing = AudtiStautsCodec.class)
  8. private AuditStatus status;
  9.  
  10. public String getTitle() {
  11. return title;
  12. }
  13.  
  14. public void setTitle(String title) {
  15. this.title = title;
  16. }
  17.  
  18. public String getContent() {
  19. return content;
  20. }
  21.  
  22. public void setContent(String content) {
  23. this.content = content;
  24. }
  25.  
  26. public AuditStatus getStatus() {
  27. return status;
  28. }
  29.  
  30. public void setStatus(AuditStatus status) {
  31. this.status = status;
  32. }
  33.  
  34. }

在通过之前的测试代码测试一下结果是否正确:

  1. public class SerializeTest {
  2. public static void main(String[] args){
  3. Article article = new Article();
  4. article.setTitle("Article 1");
  5. article.setContent("This is content");
  6. article.setStatus(AuditStatus.AUDITING);
  7.  
  8. String str = JSON.toJSONString(article);
  9. System.out.println(str);
  10.  
  11. Article article1 = JSON.parseObject(str, Article.class);
  12. System.out.println(article1.getStatus());
  13. }
  14. }

结果如下:

自定义fastjson对枚举类型的序列化及反序列化过程的更多相关文章

  1. 【json】与【枚举】的序列化和反序列化

    参考:Jackson – Deserialization from json to Java enums 问题描述 java中使用枚举时,如果涉及到restful调用,不可避免会涉及到枚举的序列化和反 ...

  2. 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)

    写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...

  3. 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

    原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...

  4. Java中Enum类型的序列化(转)

    在Java中,对Enum类型的序列化与其他对象类型的序列化有所不同,今天就来看看到底有什么不同.下面先来看下在Java中,我们定义的Enum在被编译之后是长成什么样子的. Java代码: Java代码 ...

  5. 理解Java枚举类型

    (参考资料:深入理解java enum) 1.原理:对编译后的class文件javap反编译可以看出,定义的枚举类继承自java.lang.Enum抽象类且通过public static final定 ...

  6. 用私有构造器或枚举类型强化Singleton

    Singleton指只有一个实例的类,只能被创建一次. 在Java1.5之前实现Singleton有两种方式,都是将构造器设为private并导出公有的静态成员实例. 第一种方式将公有的静态成员实例设 ...

  7. Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解

    Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全   Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...

  8. java 枚举类型分析

    最近做android开发,需要用到枚举值,这样可以连续赋值,我按之前c++那样书写,如下所示: public enum ColorSelect { RED_BAGE = 0, GREEN_BAGE, ...

  9. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

随机推荐

  1. DALI开关

    DALI开关简介 一:符合协议IEC 62386 二:DALI总线取电,低压操作,安全可靠 三:可以开,关,调光,调色温 四:DALI总线取电,低压操作,安全可靠 五:可按压开,关,旋转调光,调光器耐 ...

  2. ACL,NAT的使用

     项目练习 练习一: 练习目的:通过配置路由器的dhcp功能使pc自动获取ip地址. Router>enable Router#configure terminal Router(config) ...

  3. Python等同于PHP的 strip_tags?

    我感觉目前最好的方式 from django.utils.html import strip_tags

  4. MyBatis(二):基础CRUD

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出1便就懂!b站搜索狂神说即可 https://space.bilibili.com/95256449?spm_id_from=333.788 ...

  5. spring08

    这里主要学习的是关于spring之后中与ioc不同的aop技术:面向切面编程是spring基石之一: 解决代码混乱文体,代码分散,当部分修改时,要逐个修改当更多的日志以及验证介入之后会使代码变得更加的 ...

  6. CentOS之crontab

    1.crontab介绍 功能说明:设置计时器. 语 法:crontab [-u <用户名称>][配置文件] 或 crontab [-u <用户名称>][-elr] 补充说明:c ...

  7. Java中的垃圾回收算法详解

    一.前言   前段时间大致看了一下<深入理解Java虚拟机>这本书,对相关的基础知识有了一定的了解,准备写一写JVM的系列博客,这是第二篇.这篇博客就来谈一谈JVM中使用到的垃圾回收算法. ...

  8. k8s~helm镜像版本永远不要用latest

    对于容器编排工具k8s来说,你可以使用它规定的yaml格式的脚本,使用客户端kubectl来与k8s进行通讯,将你定义好的yaml部署脚本应用到k8s集群上,而这对yaml脚本一般来说都是很像的,就是 ...

  9. Java创建线程的三种形式的区别以及优缺点

    1.实现Runnable,Callable Callable接口里定义的方法有返回值,可以声明抛出异常. 继承Callable接口实现线程 class ThreadCall implements Ca ...

  10. 试验使用t检验

    官方解释 Excel中使用T.TEST函数 T.TEST(array1,array2,tails,type) Array1      必需.第一个数据集. Array2      必需.第二个数据集. ...