지난 포스트에서 @Cachable어노테이션 없이 Cache등록하기를 사용해보았고, 캐시의 적중 여부에 따라 Boolean 형태로 응답하는 과정을 구현해 보았다.
이번엔 적중 여부에 따라 실제 저장된 값을 가져와 반환하도록 하는 기능을 구현해보자.
그러기 위해 우선 Redis 의 캐시매니져에서 우리의 캐시를 어떻게 저장하는지 부터 알아보면
Redis-cli 에서 TYPE 를 통해 읽어왔을 때 모두 String 으로 저장된 것을 확인할 수 있다.
아하~ 그러면 다시 가져왔을땐 .toInt() 나 .toDouble() 등으로 고치면 되겠구나~
아니다.
get() 메서드를 통해 캐시에 저장된 value 를 가져왔을 때의 데이터 형은 ValueWrapper 라는 형태로 가져오게 된다.
스프링 프레임워크에서 제공하는 인터페이스로, 캐시에 저장된 값의 래퍼(wrapper) 역할을 한다. 이 인터페이스는 캐시에 저장된 값과 해당 값에 대한 메타데이터를 함께 관리한다.
일반적으로 캐시에 저장된 값을 가져올 때, 스프링 캐시 추상화 API를 사용하면 ValueWrapper 형태로 값을 가져올 수 있다. 이를 통해 실제 값에 접근할 수 있으며, 캐시에 저장된 값이 존재하지 않거나 타입이 일치하지 않는 경우에 대비하여 안전하게 처리할 수 있다.
그렇다면 우리는 ValueWrapper.get() 메서드로 Wrapper 안에 감싸여진 실제 데이터(value)를 가져오도록 하면 되는 것이다.
아하~ 그럼 인제 DTO 도 .get() 으로 가져오면 되겠구나~ 좋네~
가 아니었다.
이번엔 LinkedHashMap cannot be cast to class ~~~(dto 클래스로 변환할 수 없다~) 라고 말하고 있다.
Java에서 제공하는 클래스로, 해시맵(HashMap: 해시 테이블을 사용하여 키-값 쌍을 저장하는 자료구조)과 연결 리스트(Linked List:각 요소가 이전 요소와 다음 요소를 가리키는 포인터를 갖는 구조)의 특징을 결합한 것이다. 이 클래스는 삽입 순서 또는 접근 순서를 보존하여 요소를 저장한다.
그래서 왜 LinkedHashMap 이 튀어나왔는고 하니 직렬화/역직렬화 문제와 관련되는 문제였다.
RedisConfig 에서 CacheManager 를 정의할 때 GenericJackson2JsonRedisSerializer를 통해 역직렬화 하도록 하고 있었는데, ObjectMapper 가 우리의 DTO type 정보를 모른 채 역직렬화를 진행하기 때문에 기본타입인 LinkedHashMap 으로 역직렬화 시키고 있던 것이다.
따라서 LinkedHashMap 으로 가져온 값을 as EventResponse 를 통해 명확하게 변환할 대상을 지정해주면 원하는 결과를 얻을 수 있게 된다!!
제대로 구조를 잘 파악하지 못했을 땐 생성자 오류가 계속 떠서 어떻게든 값을 보여주기 위해 아래와 같은 삽질을 하기도 했었는데 다른 DTO 도 일일히 변환할 생각을 했다니 정말 아찔하다..