通常,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()); } }
結果如下: