[Redis] cannot deserialize from Object value (SerializationException)

2024. 10. 27. 01:42·JAVA/Application

Springboot Cache를 적용하고자 할 때 발생가능한 오류입니다.

- 저는 redis cache 사용했습니다.

- 또한 캐시 value에 대해서 GenericJackson2JsonRedisSerializer를 적용했습니다.

 


서버에 캐시를 적용했는데 만약 이런 에러를 만났다면, jackson의 역직렬화에 대해 생각해봅시다.

캐시된 응답을 올바른 객체로 내보내야 하는데 역직렬화할때 쓸 생성자가 없다면

cannot deserialize from Object value를 로그에서 만날 수 있습니다.

*생성자의 존재 문제가 아닌, 역직렬화하기 적절한 생성자를 두는 것이 핵심입니다.

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `org.springframework.http.ResponseEntity` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

 

 

일단 응답 DTO를 직렬화해서 캐시를 최초 생성해둘 때는 문제가 되지 않았을 것입니다.

(redis-cli에서 보면, 캐싱 데이터가 담긴 것을 확인할 수 있었습니다.)

하지만 캐싱된 값을 역직렬화하기 위한 장치 또한 잘 해뒀어야 합니다.

 

 

■ 해법1

아주 기본 세팅!

Dto에 기본생성자(@NoArgsConstructor)를 둬야 합니다.

 

 

■ 해법2

"생성자를 잘 처리하면" 됩니다.

다만 jackson이 직렬화/역직렬화 과정에서 모두 이해할 수 있는 형태여야 합니다.

만약 생성자에 특별한 로직이 없고, 단지 기본타입의 필드들이 파라미터를 이루고 있다면 별 문제 없을 것입니다. 하지만 만일 파라미터에 Entity를 그대로 넣었거나 어떤 복잡한 타입이 들어가 있다면 문제가 될 수 있습니다.

 

jackson 입장이 되어봅시다. Dto에 복잡한 타입이 있다면 직렬화/역직렬화 정책을 예측하지 못할 수 있습니다. 예를들어 LocalDateTime이 DTO 필드에 있다면, 직렬화할 때 예상치 못한 형태로 저장됩니다. 역직렬화하는 방법이 항상 직렬화 방법과 동일하지는 않기 때문에, 직렬화한 것을 역직렬화해내지 못할 수도 있는 것이죠. 솔루션으로 @JsonFormat 을 사용하거나 커스텀 직렬화기를 둘 수도 있고, springboot 2.x에서는 @JsonDeserialize(using = LocalDateTimeDeserializer.class), @JsonSerialize(using = LocalDateTimeSerializer.calss)로 해결할 수 있다고 합니다. (LocalDateTime 역직렬화/직렬화 문제해결 참고)

 

또한 Dto 생성자 파라미터가 '복잡한 타입'이면 역직렬화할 때 매핑이 안 됩니다.

파라미터에 Entity를 넣은 경우를 생각해봅시다. jackson은 Entity를 이해할 수 없습니다. 제가 만약 Entity를 파라미터에 넣어서 entity.getName() 이런식으로 값들을 뽑아 응답 Dto를 만들어내고 그 Dto를 캐싱했다고 가정합시다.

캐싱된 값을 역직렬화할 때 또다시 이 생성자를 사용하게 될 것입니다. 그런데 파라미터가 Entity네요? jackson은 DTO 필드의 나열을 어떤 Entity 객체로 자동 매핑하는 기능이 없습니다. 매핑 가능하도록 도와줘야 합니다.

 

단순한 해결책은 파라미터에 Entity를 받는게 아니라, 매핑이 쉬운 필드타입 파라미터로 풀어주는 것입니다. 

 

 

■ 추가설명

해결방안 중 @JsonCreator와 @JsonParameter가 있습니다.

생성자에 @JsonCreator를 붙여주고, 파라미터에 @JsonParameter("keyName") 을 붙여줘서 jackson의 json 매핑을 확실하게 돕는 것이죠. 만약 키 이름이 잘못될 경우 null이 들어갑니다. 

어떤 파라미터에 @JsonParameter("keyName")을 지정했는데 실제로 그 값이 없어서 null이 들어온다면, 단순히는 해당 Dto 필드에 null값이 들어가겠습니다. 만약 해당 필드가 객체였고 생성자 내에서 객체를 참조하고 있다면, Dto가 만들어지는 과정에서 NPE가 날 것입니다.

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `com.example.demo.XxxxxDto`, problem: `java.lang.NullPointerException`

 

 

아무튼 @JsonCreator와 @JsonParameter의 핵심도 역시 Jackson이 그 생성자를 json으로 잘 매핑할 수 있게 명시하는 것입니다. 모두 같은 맥락인 것이죠.

 

반응형

'JAVA > Application' 카테고리의 다른 글

[Spring] DTO 매핑시 특정 키만 null 값  (2) 2024.11.06
[Spring AOP] Consumer onMessage() 비동기 수신 로깅  (0) 2024.10.31
다량의 이미지 업로드 속도 최적화 / 트래픽 대비 / 비동기 처리  (0) 2024.09.23
[Spring] Cache : 프로젝트에 간단히 적용해둠  (1) 2024.03.28
[Java][Backend] null 반환 리팩터링  (0) 2024.03.08
'JAVA/Application' 카테고리의 다른 글
  • [Spring] DTO 매핑시 특정 키만 null 값
  • [Spring AOP] Consumer onMessage() 비동기 수신 로깅
  • 다량의 이미지 업로드 속도 최적화 / 트래픽 대비 / 비동기 처리
  • [Spring] Cache : 프로젝트에 간단히 적용해둠
히어로맛쿠키
히어로맛쿠키
  • 히어로맛쿠키
    yeny_lab
    히어로맛쿠키
  • 전체
    오늘
    어제
    • 분류 전체보기 (389)
      • 미분류글 (32)
        • ㅇ (2)
      • JAVA (84)
        • Effective Java (1)
        • Application (21)
      • 컴퓨터구조 & OS (28)
      • 자료구조 + 알고리즘 (43)
      • Database (12)
      • 컴파일러 (10)
      • 수학 (33)
        • 미분방정식 (12)
      • 데이터분석과 머신러닝 (38)
      • 기타 (59)
      • yyeeennyy (25)
  • 공지사항

    • ^o^/♡
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
히어로맛쿠키
[Redis] cannot deserialize from Object value (SerializationException)
상단으로

티스토리툴바