關於Redis的問題探討(二):Range方法返回的物件是LinkeHashMap以及轉換辦法

LonZyuan 發表於 2022-05-26
Redis HashMap

上一篇:關於Redis的問題探討(一):為何存放集合偏向於轉String後存放而非直接存

在上篇中發現了一個問題,明明存的是一個物件的集合,為什麼通過range方法返回的卻是LinkeHashMap

於是通過debug看看原始碼,瞭解執行流程,找一下原因

這是筆者通過debug畫出的大致流程:

關於Redis的問題探討(二):Range方法返回的物件是LinkeHashMap以及轉換辦法

注意看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)

執行測試:

關於Redis的問題探討(二):Range方法返回的物件是LinkeHashMap以及轉換辦法

 可以發現轉換成功了