在寫Java的Unit Test時,對於Unit Test所指望的值,通常是利用工具從test/resources
目錄下將expectResult.json讀取進來並用json序列化工具進行反序列化來得到Unit Test所指望的結果,並與測試的實際結果進行對比。然而如果反序列化所用的類來源於第三方庫(即不能更改任何代碼),會遇到很大的問題。如下以本人對阿里雲的StreamRecord類進行反序列化時遇到的問題進行描述:java
StreamRecord類的定義以下:git
public class StreamRecord { public enum RecordType { /** * PUT類型 * 若是對應行已存在,該Record須要覆蓋原有數據。 */ PUT, /** * UPDATE類型 * 若是對應行已存在,該Record是在原有數據上的更新。 */ UPDATE, /** * DELETE類型 * 代表要刪除對應的行。 */ DELETE } /** * Record的類型 */ private RecordType recordType; /** * 對應行的主鍵 */ private PrimaryKey primaryKey; /** * 對應行的時序信息 */ private RecordSequenceInfo sequenceInfo; /** * 該Record包含的屬性列,爲RecordColumn類型 */ private List<RecordColumn> columns; /** * 獲取Record的類型 * @return Record的類型 */ public RecordType getRecordType() { return recordType; } public void setRecordType(RecordType recordType) { this.recordType = recordType; } /** * 獲取對應行的主鍵 * @return 對應行的主鍵 */ public PrimaryKey getPrimaryKey() { return primaryKey; } public void setPrimaryKey(PrimaryKey primaryKey) { this.primaryKey = primaryKey; } /** * 獲取該行的時序信息 * @return 該行的時序信息 */ public RecordSequenceInfo getSequenceInfo() { return sequenceInfo; } public void setSequenceInfo(RecordSequenceInfo sequenceInfo) { this.sequenceInfo = sequenceInfo; } /** * 獲取該Record包含的屬性列列表 * @return 該Record包含的屬性列列表 */ public List<RecordColumn> getColumns() { if (columns != null) { return columns; } else { return new ArrayList<RecordColumn>(); } } public void setColumns(List<RecordColumn> columns) { this.columns = columns; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[RecordType:]"); sb.append(this.recordType); sb.append("\n[RecordSequenceInfo:]"); sb.append(this.sequenceInfo); sb.append("\n[PrimaryKey:]"); sb.append(this.primaryKey); sb.append("\n[Columns:]"); for (RecordColumn column : this.getColumns()) { sb.append("("); sb.append(column); sb.append(")"); } return sb.toString(); } }
本工程原先只用Jackson進行序列化和反序列化,但Jackson的ObjectMapper在對此類進行反序列化時,報了No suitable constructor
的錯誤,通過調查發現Jackson進行反序列化須要默認的構造函數(若是有帶參數的構造函數,還要用@JsonCreator
修飾構造函數,用@JsonProperty
修飾構造函數參數),而上述類沒有,即便有咱們也不能對阿里雲等第三方庫進行更改,遂放棄Jackson,轉而考慮阿里本身的fastjson。fastjson的確能對該類進行反序列化,可是當我仔細分析反序列化後的對象時,發現有些深層的字段的值爲null,又通過一番調查,瞭解到fastjson雖然對反序列化的類沒有構造函數的要求,但對字段有要求,反序列化的private字段要有setter方法才能正常的反序列化(或者有一個帶有全部字段參數的構造函數),如果private字段缺乏setter方法,則該字段的值爲默認值。最後考慮用Google的Gson,Gson沒有上述這些問題,可是若反序列化類有Object類型的字段,而該字段的值爲數值型,則Gson都會轉爲Double型,好比你有個字段爲github
private Map<String, Object> map;
json文件:編程
{ "age": 24, "height": 1.81 }
當把上述json文件反序列化爲map字段時,直覺上會認爲「age」字段的值的類型應該爲Integer或Long型,然而Gson這裏有點反常,因爲map的value爲Object類型,並未明確指定具體的數值類型,它會將key爲「age」的字段會變爲Double類型(並非咱們直覺上所指望的Integer或Long型),給後續編程帶來麻煩。關於Gson的這個「特性」,能夠參考https://github.com/google/gso... 上面的「debate」,比較有趣的「網友懟做者」。json
我最終的解決方案是用Gson反序列化,再利用反射工具ReflectionTestUtils.setField來對某些數值進行Double到Long的轉化。app
以上實驗所用版本:ide
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5' compile group: 'com.alibaba', name: 'fastjson', version: '1.2.56'
所以,若是沒有遇到序列化和反序列化第三方庫的model的狀況下(即代碼沒法更改的狀況),首選Jackson,不然選Gson。函數