我們知道,在自定義類中,若想完成序列化必須要實現Serializable接口。
那么在實現后如何進行序列化呢?
一.普通對象
序列化:
1.首先我們要定義一個? 序列化所需要的工具類?ObjectMapper?
//定義序列化所需要的工具類 轉化機器ObjectMapper objectMapper = new ObjectMapper();
2.定義所要序列化的類? (在這里以我正在做的項目中的一個類為例)
//定義所要序列化的類 轉化原料CommonResult<String> result = CommonResult.error(500, "系統錯誤");
3.調用objectMapper.writeValueAsString()方法序列化為String
//定義序列化后的類 轉化產品String str = null;//序列化try {str = objectMapper.writeValueAsString(result);} catch (JsonProcessingException e) {e.printStackTrace();}
這個方法只有一個參數,就是要序列化對象本身
打印結果
?反序列化:
//反序列化 JsonParser:反序列化所轉化的對象 ResolvedType: 所返回的對象的類型try {CommonResult<String> commonResult1 = objectMapper.readValue(str, CommonResult.class);System.out.println(commonResult1);} catch (JsonProcessingException e) {e.printStackTrace();}
這個方法有兩個參數
JsonParser:反序列化所轉化的對象(str? 剛序列化后的產物)??
ResolvedType: 所返回的對象的類型(CommonResult)
返回值就是原本對象?
打印結果:
二.List對象
序列化:
1.定義ObjectMapper (上文已經定義過)
2.初始化所要序列化的List(用于演示)
3.調用objectMapper.writeValueAsString()可見與普通對象無差別
真正的區別在反序列化
//序列化 ListList<CommonResult<String>> list = Arrays.asList(CommonResult.success("success1"),CommonResult.success("success2"));try {str = objectMapper.writeValueAsString(list);System.out.println(str);} catch (JsonProcessingException e) {e.printStackTrace();}
反序列化:
因為我們不能保證在每個List中存放的類型一致,所以在objectMapper.readValue()方法的第二個參數(類型)不能保持一致,這里引入一個新參數JavaType,也就是反序列化調用的方法參數
看名字就知道它是用于描述java中類型的,我們看看他怎么用的。
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, CommonResult.class);
1.調用objectMapper的類型工廠objectMapper.getTypeFactory()(充當工具)
2.獲取JavaType??constructParametricType()
這個方法有多個重載,這里有兩個參數:
第一個不會變,要序列化的對象類型(List)
第二個:List中的屬性類型(CommonResult)
在Map中由于Map有兩個參數所以會有第三個參數(按順序寫即可)
然后調用objectMapper.readValue()即可
List<CommonResult<String>> result2 = null;try {result2 = objectMapper.readValue(str, javaType);// System.out.println(result2);for(CommonResult<String> a : result2) {System.out.println(a.getData());}} catch (JsonProcessingException e) {e.printStackTrace();}
三.Map對象
還是按照前文,注意constructParametricType()方法傳入三個參數即可
//序列化 MapMap<Integer, CommonResult<String>> map = new HashMap<>();map.put(3,CommonResult.success("success3"));map.put(4,CommonResult.success("success4"));try {str = objectMapper.writeValueAsString(map);System.out.println(str);} catch (JsonProcessingException e) {e.printStackTrace();}//反序列化 先構造一個所需要的參數類型 Map類型 內部是什么類型JavaType javaType2 = objectMapper.getTypeFactory().constructParametricType(Map.class, Integer.class, CommonResult.class);Map<Integer, CommonResult<String>> result3 = null;try {result3 = objectMapper.readValue(str, javaType2);// System.out.println(result2);System.out.println(map.get(3).getCode());} catch (JsonProcessingException e) {e.printStackTrace();}
四.封裝成方法
在上述寫過程中try了許多的異常,非常的冗余,我們可以參考一下JacksonJsonParser源碼對這個問題解決方法。
在源碼部分對List與Map是這樣實現的:
public Map<String, Object> parseMap(String json) {return (Map)this.tryParse(() -> {return (Map)this.getObjectMapper().readValue(json, MAP_TYPE);}, Exception.class);}public List<Object> parseList(String json) {return (List)this.tryParse(() -> {return (List)this.getObjectMapper().readValue(json, LIST_TYPE);}, Exception.class);}
我們發現它并沒有進行異常捕獲,進入tryParse()方法看一下:
protected final <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {try {return parser.call();} catch (Exception var4) {if (check.isAssignableFrom(var4.getClass())) {throw new JsonParseException(var4);} else {ReflectionUtils.rethrowRuntimeException(var4);throw new IllegalStateException(var4);}}}
原來是在這里進行了異常處理。通過在tryParse()方法傳入lambda表達式然后再call()返回(這一步并沒有進行實際業務執行,單純為了將處理異常這一步統一處理)。再判斷調用lambda時不活的異常是否是原業務的異常,如果不是就再爆其他的異常。
我們參照這個解決邏輯,完成一個在項目中使用的JacksonUtil類。
同時注意到在源碼部分對ObjectMapper這個一直用的對象進行了單例模式的實現,我們也學習一下。
1.單例模式實現ObjectMapper
/*** 單例模式實現ObjectMapper*/private static final ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER = new ObjectMapper();}//構造方法私有化private JacksonUtil() {}//獲取OBJECT_MAPPER對象public ObjectMapper getObjectMapper() {return JacksonUtil.OBJECT_MAPPER;}
2.解決try catch太多的方法
我們可以直接復制源碼部分的tryParse代碼
只需把final改為static(方便其他方法調用)
else判斷的部分也可以不要(jdk自己對異常的補充,可以不要)
protected static <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {try {return parser.call();} catch (Exception var4) {if (check.isAssignableFrom(var4.getClass())) {throw new JsonParseException(var4);}throw new IllegalStateException(var4);}}
我們可以對這個方法進行封裝一下:
/*** 封裝tryParse方法 使其固定爆出JacksonException異常* @param parser 傳入的lambda表達式* @param <T>* @return*/private final <T> T tryParse(Callable<T> parser) {return JacksonUtil.tryParse(parser, JacksonException.class);}
3.實現序列化
由于普通對象與List Map的序列化過程幾乎相同,所以我們一個方法就可以實現。
/*** 序列化 對普通對象 與 List 都適用* @param object* @return*/public static String writeValueAsString(Object object) {return JacksonUtil.tryParse(() -> {return JacksonUtil.getObjectMapper().writeValueAsString(object);});}
4.實現反序列化
普通對象序列化:
/*** 普通對象反序列化* @param content* @param valueType* @param <T>* @return*/public static <T> T readValue(String content, Class<T> valueType) {return JacksonUtil.tryParse(() -> {return JacksonUtil.getObjectMapper().readValue(content, valueType);});}
List反序列化:注意將第二個參數類型改為?Class<?>而不是??Class<T>
/*** 反序列化 List* @param content* @param paramClasses* @param <T>* @return*/public static <T> T readListValue (String content, Class<?> paramClasses) {JavaType javaType = JacksonUtil.getObjectMapper().getTypeFactory().constructParametricType(List.class, paramClasses);return JacksonUtil.tryParse(() -> {return JacksonUtil.getObjectMapper().readValue(content, javaType);});}
最后附上測試代碼:
@Testvoid jackUtilTest() {CommonResult<String> result = CommonResult.error(500, "系統錯誤");String str = JacksonUtil.writeValueAsString(result);System.out.println(str);CommonResult<String> commonResult = JacksonUtil.readValue(str, CommonResult.class);System.out.println(commonResult);//序列化 ListList<CommonResult<String>> list = Arrays.asList(CommonResult.success("success1"),CommonResult.success("success2"));String str1 = JacksonUtil.writeValueAsString(list);System.out.println(str1);list = JacksonUtil.readListValue(str1, CommonResult.class);for(CommonResult<String> a : list) {System.out.println(a.getData());}}