게시글 및 리뷰에 대한 인기글 조회를 구현하면서 일정 시간마다 데이터를 Cache해서 보여주기 위해 Redis Cache를 사용했다.
초기 RedisConfig 코드는 다음과 같다.
@Configuration
@EnableCaching
class RedisCacheConfig {
@Bean
fun redisCacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager =
RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(
RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
)
.build()
}
직렬화에 대한 별도 설정을 하지 않았기 때문에 Redis에 저장되는 데이터는 다음과 같이 저장되어 있지만, 역직렬화 시에는 데이터 값이 첫 줄에 있는 class type 정보를 이용해 역직렬화 하기 때문에 정상적인 형태로 출력된다.
직렬화 설정으로 저장되는 데이터도 보기 쉽도록 바꾸기 위해 RedisCacheCofig 코드를 다음과 같이 변경하였다.
@Configuration
@EnableCaching
class RedisCacheConfig {
@Bean
fun redisCacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager =
RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(
RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
.serializeKeysWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(StringRedisSerializer())
)
.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(
GenericJackson2JsonRedisSerializer()
)
)
)
.build()
}
위 코드 그대로 서버를 실행하고 요청을 보내면 다음과 같은 예외가 발생한다.
Jackson 라이브러리가 Java 8의 ZonedDateTime 타입을 지원하지 않기 때문에 발생하는 문제이다.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Java 8 date/time type `java.time.ZonedDateTime` not supported by default:
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain:
java.util.ArrayList[0]->spartacodingclub.nbcamp.kotlinspring.project.team4ighting.spring4gamer.domain.gamereview.dto.response.GameReviewResponse["createdAt"])
위 문제를 해결하기 위해 ObjectMapper를 사용해 JavaTimeModule을 추가하면 되지만, 다음 예외 메시지처럼 또 다른 문제가 발생한다.
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: object is not an instance of declaring class]
이유는 단순히 List형태의 JSON 데이터가 들어가기 때문 class type에 대한 정보가 없다.
(처음 데이터가 저장된 이미지를 보면 class type이 같이 저장되어 있는 것을 볼 수 있다.)
GenericJackson2JsonRedisSerializer는 기본적으로 class type 정보를 함께 저장하지만 Custom ObjectMapper를 등록하면 직렬화/역직렬화 시 class type 정보를 포함하지 않기 때문에 문제가 발생한 것이다.
RedisCacheCofig 코드를 다시 한 번 수정해서 다음과 같이 작성한다.
@Configuration
@EnableCaching
class RedisCacheConfig {
@Bean
fun redisCacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager =
RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(
RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
.serializeKeysWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(StringRedisSerializer())
)
.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(
GenericJackson2JsonRedisSerializer(
jacksonObjectMapper()
.registerModules(JavaTimeModule())
.activateDefaultTyping(
BasicPolymorphicTypeValidator
.builder()
.allowIfSubType(Object::class.java)
.build(),
ObjectMapper.DefaultTyping.NON_FINAL
)
)
)
)
)
.build()
}
- activateDefaultTyping
- 기본 타이핑 활성화
- 직렬화된 JSON에 클래스 정보를 포함시켜, 역직렬화 시에 원래의 객체 타입을 복원할 수 있게 하는 기능
- BasicPolymorphicTypeValidator
- Jackson 라이브러리에서 제공하는 클래스
- 다형성을 가진 객체를 직렬화하거나 역직렬화할 때 사용
- 역직렬화할 실제 하위 유형이 지정된 기준에 따라 유효한지 확인하는 데 사용
서버를 실행 후 요청을 보내면 다음과 같이 보기 좋게 class type과 데이터를 확인 할 수 있다.
- Inheritance in Jackson | Baeldung
- BasicPolymorphicTypeValidator (The Adobe AEM Quickstart and Web Application.)
'TIL(Today I Learned)' 카테고리의 다른 글
TIL - S3 Presigned URL을 통해 이미지 파일 업로드 (0) | 2024.08.26 |
---|---|
TIL - ZonedDateTime 사용 시 Converter로 DB와의 시간 차 해결 (0) | 2024.07.22 |
TIL - PostMan에서 Token을 Global로 적용 (0) | 2024.07.17 |
TIL - IntelliJ에서 Git Flow 사용 (0) | 2024.07.16 |
TIL - Connection Pool (0) | 2024.07.10 |