Spring/문제 해결 (Troubleshooting)

@Cacheable 사용 시 역직렬화 오류 해결

가지코딩 2025. 7. 15. 11:15

문제 상황

@Cacheable(value = "books", key = "...")
public PagedResponse<BookResponseDto> findAllCached(...) {
    return bookService.findAll(...);
}

 

 

PagedResponse<BookResponseDto> 와 같은 제네릭 타입으로 캐싱할 때

캐시에서 조회된 데이터가 LinkedHashMap으로 역직렬화되어 아래와 같은 오류가 발생

 

 

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class cohttp://m.example.book_api.global.dto.PagedResponse (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; cohttp://m.example.book_api.global.dto.PagedResponse is in unnamed module of loader 'app')

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.example.book_api.global.dto.PagedResponse (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.example.book_api.global.dto.PagedResponse is in unnamed module of loader 'app')

2. 원인 분석

  • @Cacheable 내부에서 Jackson이 객체를 JSON으로 직렬화하고 역직렬화하는 과정에서 제네릭 타입 정보가 손실된다.
  • Java의 타입 소거(Type Erasure) 특성 때문에 런타임에 제네릭 타입을 정확히 알 수 없어,
  • 역직렬화 시 기본적으로 LinkedHashMap 타입으로 변환하게 된다.

3. 해결 방법

직접 캐시 로직 구현 및 TypeReference 사용

  • 자동 캐시 대신 RedisTemplate 등으로 직접 캐시를 관리한다.
  • ObjectMapper에 TypeReference를 명시해 정확한 타입으로 역직렬화한다.
// 역 직렬화 문제로 수동 캐싱
public PagedResponse<BookResponseDto> findAllCached(...) {

    // key 조회
    String key = ...;
    Object cached = redisTemplate.opsForValue().get(key);
    PagedResponse<BookResponseDto> cachedResponse = objectMapper.convertValue(
            cached,
            new TypeReference<PagedResponse<BookResponseDto>>() {}
    );

    // 저장된 캐시가 있으면, 캐시 값 출력
    if (cachedResponse != null) {
		...
        return cachedResponse;
    }

    // 저장된 캐시가 없으면, DB 조회 + 캐시 생성
    PagedResponse<BookResponseDto> result = bookService.findAll(...);
    redisTemplate.opsForValue().set(key, result, 30, TimeUnit.MINUTES);

    return result;
}