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

結果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM