[java/Spring/Redis] Spring Redis 역직렬화 - 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 ha

nana·2024년 11월 4일
0

Trouble Shooting

목록 보기
3/4

Caused by: 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: com.tdd.ecommerce.product.domain.entity.Product["regDate"])

문제 이유

Redis Cache를 적용하려고 했더니 해당 오류가 발생했다.

 @Cacheable(value = "getProductInfo"
            , key = "#productId"
            , unless = "#productId == null")
    public Product getProductById(Long productId) {
        Product product = productRepository.findByProductId(productId);

        if(product == null)
            throw new BusinessException(ECommerceExceptions.INVALID_PRODUCT);
        return product;
    }

LocalDateTime 타입이 Jackson에서 기본적으로 지원되지 않아 발생하는 문제.

Spring Data Redis에서 LocalDateTime을 직렬화하려면 jackson-datatype-jsr310 모듈을 추가하여 Jackson이 Java 8의 날짜와 시간 타입을 지원할 수 있도록 설정해야 한다.

해결방법

  1. jackson-datatype-jsr310 라이브러리 추가
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.15.2</version> <!-- 최신 버전 사용 -->
</dependency>

xml

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2' // 최신 버전 사용

gradle

이거만 추가하면 되는게 아니라,
LocalDateTime을 쓰는 regDate, editDate 부분에 직렬화, 역직렬화 코드를 추가해 주어야 한다.

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class TimeStamped {

    @CreatedDate
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonFormat(pattern ="yyyy-MM-dd kk:mm:ss")
    @Column(updatable = false, nullable = false)
    private LocalDateTime regDate;

    @LastModifiedDate
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonFormat(pattern ="yyyy-MM-dd kk:mm:ss")
    @Column(nullable = true)
    private LocalDateTime editDate;
}
  1. ObjectMapper 설정
    ObjectMapper에 JavaTimeModule을 등록.
    Spring Boot에서 기본적으로 Jackson이 사용되므로, JavaTimeModule을 등록하는 @Bean을 생성하여 설정할 수 있음.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        return mapper;
    }
}
  1. RedisTemplate 설정
    Redis에서 JSON 직렬화 시 Jackson이 이 ObjectMapper를 사용하도록 설정.
    RedisTemplate의 Jackson2JsonRedisSerializer에 등록한 ObjectMapper를 전달하여 LocalDateTime 타입을 직렬화할 수 있도록 한다.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        serializer.setObjectMapper(mapper);

        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        return template;
    }
}

Object Mapper

ObjectMapper는 Java에서 JSON을 다루는 데 사용되는 Jackson 라이브러리의 주요 클래스.
주로 JSON과 Java 객체 간의 변환(즉, 직렬화 및 역직렬화)을 담당한다.

  • 직렬화(Serialization) : Java 객체를 JSON으로 변환하는 과정
  • 역직렬화(Deserialization) : JSON을 Java 객체로 변환하는 과정
  • ObjectMapper는 이러한 직렬화 및 역직렬화 작업을 수행하는 다양한 메서드를 제공.
  • 컬렉션 타입, 날짜/시간 타입과 같은 복잡한 데이터 유형을 적절하게 처리하기 위해서는 사용자 정의 모듈을 추가하는 기능도 제공.

Java8 LocalDateTime문제 해결
참고2

profile
BackEnd Developer, 기록의 힘을 믿습니다.

0개의 댓글