피드로 돌아가기
컬리 기술블로그Backend
원문 읽기
Spring Boot 버전업 중 알게된 Java 버전별 캡슐화 정책 강화
Spring Boot 3.2.4 + Java 17 업그레이드 과정에서 Java 모듈 시스템의 강화된 캡슐화 정책으로 Gson 직렬화 실패 → Custom TypeAdapter 구현으로 해결
AI 요약
Context
AWS MSK 버전업에 따라 Spring Boot 2.5.3에서 3.2.4로, Java 11에서 17로 업그레이드하던 중 로그인 시 ValidToken 객체를 Redis에 저장하는 과정에서 Gson 직렬화 오류 발생했습니다. LocalDateTime 필드의 private 접근으로 인해 InaccessibleObjectException이 발생했습니다.
Technical Solution
- Gson의 TypeAdapter 찾기 메커니즘 분석: typeTokenCache 캐시 확인 후 등록된 TypeAdapterFactory 리스트 순회하여 적절한 어댑터 선택
- ReflectiveTypeAdapterFactory의 리플렉션 기반 접근 방식 이해: AccessibleObject.setAccessible(true)를 호출하여 private 필드에 접근하는 동작 원리 파악
- Java 9 모듈 시스템 도입 이후 버전별 캡슐화 정책 변화 추적: Java 9의 완화된 강력한 캡슐화(relaxed strong encapsulation)에서 Java 17의 강화된 모듈 접근 제어로 변화
- LocalDateTime 타입을 위한 Custom TypeAdapter 구현: ISO_LOCAL_DATE_TIME 포맷터를 사용한 write/read 메서드 정의
- Custom TypeAdapter 등록 우선순위 활용: 기본 ReflectiveTypeAdapterFactory보다 먼저 실행되도록 TypeAdapterFactory 리스트에 등록
Key Takeaway
현상 수준의 문제 해결을 넘어 근본 원인(Java 모듈 시스템의 단계적 강화)을 추적하면, 동일 패턴의 문제에 대해 일반화된 대응 방안을 수립할 수 있습니다. 내부 패키지(java.*)의 private 필드를 직렬화하는 라이브러리를 사용할 때는 명시적 TypeAdapter 구현이 필수 패턴이 됩니다.
실천 포인트
Java 17 이상 환경에서 Gson을 사용하여 java.time 패키지의 LocalDateTime, LocalDate 등을 포함한 객체를 Redis에 직렬화하는 경우, 해당 타입별 Custom TypeAdapter를 구현하고 GsonBuilder에 등록하면 모듈 시스템의 접근 제한을 회피하고 안정적인 직렬화를 보장할 수 있습니다.