上一篇:關於Redis的問題探討(一):為何存放集合偏向於轉String後存放而非直接存
在上篇中發現了一個問題,明明存的是一個物件的集合,為什麼通過range方法返回的卻是LinkeHashMap
於是通過debug看看原始碼,瞭解執行流程,找一下原因
這是筆者通過debug畫出的大致流程:
注意看8中,mapObject方法,這裡就是返回LinkeHashMap的原因,這裡重點解析一下mapObject方法:
protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOException {
// 獲取欄位名稱,也就是key String key1 = p.getText();
// 執行前該token是FIELD_NAME,也就是欄位名稱
// 然後執行nextToken()後,變為了VALUE_STRING,也就是String型別的欄位值
// 但是如果值不為String型別,那就會在後面又執行一次nextToken,變為VALUE_NUMBER_INT,也就是整數型欄位值 p.nextToken(); Object value1 = this.deserialize(p, ctxt); String key2 = p.nextFieldName(); if (key2 == null) { LinkedHashMap<String, Object> result = new LinkedHashMap(2); result.put(key1, value1); return result; } else {
// 解釋在上面 p.nextToken();
// 獲取value值 Object value2 = this.deserialize(p, ctxt); String key = p.nextFieldName(); LinkedHashMap result; if (key == null) { result = new LinkedHashMap(4); result.put(key1, value1); result.put(key2, value2); return result; } else { result = new LinkedHashMap(); result.put(key1, value1); result.put(key2, value2); do { p.nextToken(); result.put(key, this.deserialize(p, ctxt)); } while((key = p.nextFieldName()) != null); return result; } } }
首先就是這個p也就是JsonParser物件,他是通過JsonFactory的createParser方法建立的,其作用是解析Json字串,因此在執行之前mapObject之前就已經將value解析並存入JsonParser中了。
JsonParser解釋參考:https://blog.csdn.net/LBWNB_Java/article/details/120003565
然後執行流程可以參考註釋
以上就是為何返回LinkeHashMap的原因,那麼如何解決呢
這裡就要用到ObjectMapper,在range方法的流程圖中也看到其實也使用了他
通過ObjectMapper的convertValue方法將LinkeHashMap轉為目標物件:
@Test public void testRange() { String key = "right_push_all_01"; List<LinkedHashMap<String, Object>> linkedHashMapList = redisService.lRange(key, 0, -1); ObjectMapper objectMapper = new ObjectMapper(); List<ThisIsDTO> thisIsDTOList = objectMapper.convertValue(linkedHashMapList, new TypeReference<List<ThisIsDTO>>() { }); for (ThisIsDTO thisIsDTO : thisIsDTOList) { System.out.println(thisIsDTO.getAge()); } }
注意:因為是集合存放,所以一定要new TypeReference<List<ThisIsDTO>>來定義轉換的型別
如果只是單個物件,可以直接 objectMapper.convertValue(linkedHashMap, ThisIsDTO.class)
執行測試:
可以發現轉換成功了