티스토리 뷰

반응형

Redis를 사용하던 와중 특정 오류가 잡혀 골치 아픈 적이 있었다.

public class CacheConfig {
    private final RedisConnectionFactory redisConnectionFactory;

    @Bean
    public CacheManager cacheManager() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.
                        SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofSeconds(30));

        return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(redisCacheConfiguration).build();
    }
}

기존 코드는 이렇다. 이후 잘 동작하나 확인하기 위해 Postman을 사용해봤더니 문제가 발생하였다....

org.springframework.data.redis.serializer.SerializationException: Could not write JSON: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: me.golf.blog.domain.board.dto.BoardDTO["lastModifiedAt"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: me.golf.blog.domain.board.dto.BoardDTO["lastModifiedAt"])
at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.serialize(GenericJackson2JsonRedisSerializer.java:124) ~[spring-data-redis-2.6.3.jar:2.6.3]
at org.springframework.data.redis.serializer.DefaultRedisElementWriter.write(DefaultRedisElementWriter.java:44) ~[spring-data-redis-2.6.3.jar:2.6.3]

Jackson에서 Java 8에서 추가된 LocalDateTime 타입을 직렬화/역직렬화 하지 못해서 문제가 발생한 것이다. (본 프로젝트에서는 Redis를 사용해서 데이터 캐싱을 하고 있는 데 이 때 객체를 직렬화 하여 저장한다.)

직렬화 할 때 전략을 바꿔줄 필요성이 있다. 그래서 아까 해당 필드에 다음과 같이 추가적으로 @Bean을 등록해주었다.

public class CacheConfig {
    private final RedisConnectionFactory redisConnectionFactory;

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .findAndRegisterModules()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .registerModule(new JavaTimeModule());
    }

    @Bean
    public CacheManager cacheManager() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.
                        SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper())))
                .entryTtl(Duration.ofSeconds(30));

        return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(redisCacheConfiguration).build();
    }
}

위 코드를 설명하자면

  • .enable(SerializationFeature.INDENT_OUTPUT)
    • Jackson에서 Json을 좀 더 이쁘게 표현해준다.
  • .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
    • Timestamp 형태로 저장하지 않게 설정한다.
  • .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    • Timestamp 형태로 저장하지 않게 되면 LocalDateTime은 지원하지 않는 형식이 되어버린다. 그럼 에러가 발생하는데 이러한 현상을 막아줄 수 있게 false로 바꾸어 무시하게 한다.
  • .registerModule(new JavaTimeModule())
    • 역 직렬화 시 LocalDateTime 형식으로 저장할 수 있게 JavaTimeModule을 이용하여 Timestamp로 객체에 저장하게 도와준다.

자 모두 마쳤다. 이제 다시 postman으로 다시 테스트를 해보자 

정상적으로 조회 되고 LocalDateTime 타입인 lastModifiedAt도 정상적으로 역직렬화가 되는 것을 확인할 수 있다. 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함