有些時候,我們在和外部系統交互的時候使用了json作為標准的數據交換格式,同時為了安全性考慮,增加了對報文的校驗,因此我們需要確保序列化的時候參數有序且不多不少剛好,因為對外的API不像后台和前端交互一樣,兼容即可,而是對嚴謹性的要求極高。jackson默認的機制是序列化的時候,先父類的屬性,然后再是子類的屬性按照定義的順序進行(fastjson則剛好相反,先序列化子類,然后序列化父類)。為了使用json的工具類,且達到有序的目的,之前特地研究了fastjson/jackson兩者的序列化特性,fastjson/jackson都有設置序列化順序的參數,也就是jackson @JsonProperty注解的index以及fastjson @JSONField注解的ordinal。實際設置了測試下來,感覺兩者都不生效或者有bug,總之行為比較怪異。之前記得jackson有個類級別的@JsonInclude注解可以設置要序列化的所有屬性,於是特地測試了,符合預期的要求,不過記錯了是JsonIgnoreProperties。結合繼承+@JsonFormat注解,我們甚至可以完美的達到對於一個相同的屬性比如狀態,有些view要稱為orderStatus,另外一些稱為shippingStatus的目標,同時確保在service/mapper層,完全是場景無關的。jacksonJsonIgnoreProperties/JsonPropertyOrder在序列化和反序列化時僅讀取當前類的注解,忽略父類的注解,這樣我們就可以做到行為的100%精確控制,同時盡可能的復用了父類的定義。
如下:
package tf56.lf.lfoms.model.pub; import java.io.Serializable; import java.util.List; import javax.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import lombok.Getter; import lombok.Setter; import tf56.lf.base.metadata.validate.ValidServices; import tf56.lf.common.util.JacksonHelper; import tf56.lf.lfoms.validate.group.Group; /** * @author admin * */ @Getter @Setter @Deprecated @JsonPropertyOrder({"fromOutPartyType","receiverMobile","sessionBean"}) @JsonIgnoreProperties({"businessPartId","omsPaymentCollectionList","requestOrderNo"}) public class TmsCreateRequestOrderIQReqDTO extends TmsCreateRequestOrderMainReqDTO implements Serializable{ private static final long serialVersionUID = 8617922710046163090L; //費用list @ValidServices(services = Group.RQUERSTORDER_CREATE ) @NotNull @JsonFormat private List<CreateOmsPaymentCollectionReq> omsPaymentCollectionList; //貨物列表 @ValidServices(services = Group.RQUERSTORDER_CREATE ) @NotNull private List<CreateGoodsDOReq> goodsList; public static void main(String[] args) { TmsCreateRequestOrderIQReqDTO dto = new TmsCreateRequestOrderIQReqDTO(); System.out.println(JacksonHelper.toJSON(dto)); } }
在TmsCreateRequestOrderMainReqDTO類上設置了:
@JsonPropertyOrder({"sessionBean","fromOutPartyType","receiverMobile"})
@JsonIgnoreProperties({"senderMobile"})
輸出如下:
{"fromOutPartyType":null,"receiverMobile":null,"sessionBean":null,"tfSign":null,"senderPartyId":null,"senderName":null,"senderMobile":null,"fromDistrict":null,"fromAddress":null,"senderOrganization":null,"toOutPartyType":null,"receiverPartyId":null,"receiverPartyName":null,"toDistrict":null,"toAddress":null,"receiverOrganization":null,"carriersPartyId":null,"carriersCompany":null,"clientNumber":null,"transportMethod":null,"deliveryMethod":null,"isNeedReceipt":null,"receiptMethod":null,"receiptNum":null,"orderSource":null,"terminal":null,"memo":null,"goodsList":null}
不過總的來說,Jackson應該提供JsonProperties注解,畢竟僅提供ignore,不提供正向的總會有些時候無法直接滿足一樣,就像黑白名單一樣的道理。
不過這只是解決了單項的序列化問題,反序列化的時候,同樣需要解決。如果暴露的接口直接通過json requestbody映射進來,就只能定義一個一一對應的接口代理類來映射了。