본문으로 이동
문서

Spring Boot 버전업 중 알게된 Java 버전별 캡슐화 정책 강화

고산하 · 컬리 · 컬리 기술 블로그

원본 보기

소개

자바 모듈 시스템의 변화로 인한 직렬화 문제를 분석하면서 알게된 내용을 공유합니다.

AI 핵심 요약

Spring Boot와 Java를 업그레이드한 뒤 로그인 과정에서 Redis에 저장할 `ValidToken`을 Gson으로 직렬화할 때, `LocalDateTime`의 private 필드에 접근하지 못하는 `InaccessibleObjectException`이 발생했습니다. 원인을 추적한 결과 Gson의 기본 `ReflectiveTypeAdapterFactory`가 리플렉션으로 필드를 처리하는 방식과 Java 모듈 시스템의 캡슐화 강화가 충돌한 것이었습니다. `LocalDateTime`을 ISO 형식 문자열로 읽고 쓰는 커스텀 `TypeAdapter`를 등록해 기본 리플렉션 처리를 우회했고, 직렬화 문제를 해결했습니다. 버전업 오류는 임시 옵션으로 덮기보다 라이브러리의 동작과 런타임 정책 변화를 함께 살펴 근본 원인을 파악하는 것이 중요하다는 점을 보여줍니다.

  • Java 17에서는 모듈 경계가 리플렉션에도 적용되므로, JDK 타입의 private 필드에 `setAccessible(true)`로 접근하는 방식은 실패할 수 있습니다.
  • Gson은 등록된 `TypeAdapter`를 먼저 찾고, 적합한 어댑터가 없으면 `ReflectiveTypeAdapterFactory`로 필드를 처리합니다.
  • `LocalDateTime`처럼 JDK 타입을 직렬화할 때는 내부 필드를 탐색하기보다 `DateTimeFormatter`를 이용한 명시적 변환을 구현하세요.
  • `--add-opens`로 접근을 허용하는 것보다 필요한 타입에 전용 어댑터를 등록하면 캡슐화를 유지하면서 직렬화 형식을 통제할 수 있습니다.