zoukankan      html  css  js  c++  java
  • 自定义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类:

     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)。

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

    测试代码:

    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());
        }
    }

    结果如下:

  • 相关阅读:
    Spring boot mvn
    软考
    java
    webserver代理生成本地类的两种方式
    行转列语句,记录一下
    React.PureComponent浅比较理解
    关于职业规划和职场规则以及未来发展发方向
    程序员的一天
    代码commit规范
    element UI 使用总结
  • 原文地址:https://www.cnblogs.com/insaneXs/p/9515803.html
Copyright © 2011-2022 走看看