Jakarta EE 10에서 11로 올릴 때 Spring 환경의 주요 리스크

반응형
Jakarta EE 10에서 11로 올릴 때 Spring 환경의 주요 리스크

Jakarta EE 10에서 11로 올릴 때 Spring 환경의 주요 리스크

Jakarta EE 10에서 Jakarta EE 11로 넘어가는 변화는 과거의 javax.*에서 jakarta.*로 바뀌던 수준의 대격변은 아닙니다. 하지만 기존 Spring 환경에서는 Java 버전, Spring Framework 세대, 내장 서버, JPA, Validation, XML/SOAP 연계 라이브러리에서 실제 장애가 발생할 수 있습니다.

핵심은 Jakarta EE 11 API만 올린다고 업그레이드가 끝나는 것이 아니라는 점입니다. 관리자 입장에서 보면 애플리케이션 코드보다 의존성 트리, 런타임 서버, 빌드 도구, 테스트 환경의 불일치가 먼저 문제를 일으키는 경우가 많습니다.

Jakarta EE 10과 11의 큰 차이

구분 Jakarta EE 10 Jakarta EE 11 Spring 환경 영향
Java 기준 Java 11 이상 흐름 Java 17 이상 기준 JDK, CI/CD, 컨테이너 이미지, 운영 서버 JVM 확인 필요
Spring 기준 Spring Boot 3.x, Spring Framework 6.x와 주로 연결 더 최신 Jakarta API 조합 확인 필요 Boot가 관리하는 의존성 버전을 우회하면 충돌 가능
Servlet Servlet 6.0 Servlet 6.1 Tomcat, Jetty, Undertow 버전 확인 필요
Persistence Jakarta Persistence 3.1 Jakarta Persistence 3.2 Hibernate, JPQL, 엔티티 매핑, 트랜잭션 테스트 필요
Validation Jakarta Validation 3.0 Jakarta Validation 3.1 Hibernate Validator, EL 구현체, Bean Validation 초기화 확인 필요
제거·변경 EE 10 플랫폼 구성 유지 Managed Beans 제거, XML Binding·XML Web Services·SAAJ 플랫폼 제외 레거시 SOAP/XML 연계 시스템에서 영향 가능성 큼
Jakarta EE 10에서 11로의 전환은 패키지명 변경보다 런타임 기준 상향과 스펙 구성 변경에 가깝습니다.
이미 jakarta.* 패키지를 쓰고 있더라도 Java 17, 구현체 버전, 외부 WAS, SOAP/XML 의존성을 함께 봐야 합니다.
특히 Spring Boot의 BOM 관리 범위를 벗어나 Jakarta API를 개별 고정하면 컴파일 이후 실행 단계에서 문제가 드러날 수 있습니다.

1. 라이브러리 관점 리스크

Spring Boot가 관리하는 버전과 직접 선언한 Jakarta API가 충돌할 수 있음

Spring Boot 프로젝트는 보통 spring-boot-dependencies를 통해 Servlet, Validation, Persistence, Jackson, Hibernate, Tomcat 같은 주요 라이브러리 버전을 함께 관리합니다. 그런데 Jakarta EE 11로 올린다는 이유로 jakarta.servlet-api, jakarta.persistence-api, jakarta.validation-api 등을 직접 최신 버전으로 고정하면 Boot가 검증한 조합에서 벗어날 수 있습니다.

이때 자주 발생하는 문제는 컴파일은 되지만 실행 시점에 NoSuchMethodError, ClassNotFoundException, LinkageError가 터지는 형태입니다. API jar와 실제 구현체 jar의 세대가 다르면 이런 문제가 발생합니다.

mvn dependency:tree | grep -E "jakarta|javax|hibernate|tomcat|jetty|validator"

./gradlew dependencies | grep -E "jakarta|javax|hibernate|tomcat|jetty|validator"

Hibernate 5.x 또는 오래된 Validator가 남아 있으면 위험함

Jakarta EE 11에서는 Persistence와 Validation 영역도 업데이트됩니다. 기존 프로젝트가 Hibernate 5.x, 오래된 Hibernate Validator, 별도 EL 구현체를 직접 물고 있다면 JPA 엔티티 로딩, 검증기 초기화, Query 실행 단계에서 문제가 발생할 수 있습니다.

  • jakarta.persistence-api와 Hibernate 구현체 버전 불일치
  • jakarta.validation-api와 Hibernate Validator 버전 불일치
  • jakarta.el-api는 있으나 실제 EL 구현체가 없는 경우
  • Spring Boot starter가 제공하는 조합과 직접 선언 버전이 섞인 경우

SOAP, JAXB, SAAJ 계열은 별도 확인이 필요함

일반적인 REST API 서버라면 영향이 작을 수 있지만, 공공기관 연계, 금융권 대외계, 레거시 ERP 연동처럼 SOAP/XML 기반 통신을 사용하는 시스템은 Jakarta EE 11 전환에서 별도 라이브러리 의존성을 반드시 확인해야 합니다.

JAXB, JAX-WS, SAAJ, wsimport 기반 코드 생성, XML Binding을 사용하는 경우 플랫폼에 포함되어 있다고 가정하면 안 됩니다. 필요한 API와 구현체를 명시적으로 관리해야 하며, Spring Boot가 자동으로 해결해주는 영역이 아닌 경우도 많습니다.

2. 런타임 관점 리스크

Java 17 이상이 모든 실행 경로에 적용되어야 함

Jakarta EE 11 전환에서 가장 먼저 확인할 지점은 Java 버전입니다. 개발 PC만 Java 17 이상이어도 충분하지 않습니다. 빌드 서버, Jenkins, GitHub Actions, Docker base image, 운영 서버의 systemd 스크립트, 외부 WAS의 JVM 설정까지 같은 기준으로 맞아야 합니다.

java -version
javac -version
mvn -version
gradle -version

Java 버전이 맞지 않으면 다음과 같은 오류가 발생할 수 있습니다.

Unsupported class file major version
class file has wrong version
java.lang.UnsupportedClassVersionError

내장 Tomcat과 외부 WAS의 기준이 다를 수 있음

Spring Boot 내장 Tomcat을 사용하는 경우에는 Boot 버전이 관리하는 Tomcat 버전을 확인해야 합니다. 반대로 외부 WAS에 war로 배포하는 구조라면 애플리케이션보다 WAS의 Jakarta EE 지원 수준이 더 중요합니다.

배포 방식 확인할 지점 예상 문제
Spring Boot jar Boot가 가져오는 Tomcat, Jetty, Undertow 버전 Servlet API 버전 불일치, 필터·인터셉터 초기화 실패
외부 WAS war WAS가 Jakarta EE 11 또는 필요한 스펙을 지원하는지 배포 실패, 클래스 로딩 충돌, 서버 제공 API와 애플리케이션 API 중복
컨테이너 이미지 JDK 버전, base image, 실행 옵션 로컬은 성공하지만 운영 컨테이너에서 기동 실패
위험한 조합은 Spring Boot 3.x + 구버전 Tomcat 9, Spring Framework 6 + javax 기반 WAS, Jakarta EE 11 API + Jakarta EE 10 구현체처럼 API와 런타임이 서로 다른 세대를 바라보는 경우입니다.
이런 조합은 컴파일 단계보다 애플리케이션 기동, 요청 처리, 배포 시점에 더 많이 드러납니다.

3. 빌드 관점 리스크

Maven과 Gradle 설정이 Java 17 기준으로 정리되어야 함

Jakarta EE 11로 넘어가려면 빌드 도구의 Java target도 함께 정리해야 합니다. 단순히 운영 서버 JDK만 올리고 sourceCompatibility, targetCompatibility, Maven compiler 설정이 예전 값으로 남아 있으면 빌드와 실행 환경이 어긋날 수 있습니다.

<properties>
  <java.version>17</java.version>
</properties>
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

javax와 jakarta가 의존성 트리에 같이 남을 수 있음

기존 Spring 환경에서 가장 흔한 문제 중 하나는 애플리케이션 코드는 jakarta.*로 바꿨지만, 하위 라이브러리 중 일부가 여전히 javax.* 기반 API를 끌고 오는 경우입니다.

특히 다음 영역은 의존성 전이를 통해 오래된 API가 섞이기 쉽습니다.

  • 구버전 Swagger 또는 OpenAPI 라이브러리
  • 구버전 QueryDSL, MapStruct, annotation processor
  • JAXB, activation, mail 관련 라이브러리
  • 구버전 security, OAuth, SAML 연계 모듈
  • 외부 솔루션 SDK 또는 사내 공통 라이브러리
mvn dependency:tree | grep "javax"

./gradlew dependencies | grep "javax"

BOM을 섞어 쓰면 버전 정합성이 깨질 수 있음

Spring Boot BOM, Jakarta EE BOM, Hibernate BOM을 동시에 가져오면서 우선순위가 꼬이면 의도하지 않은 버전이 선택될 수 있습니다. 이 경우 IDE에서는 정상으로 보이지만 CI 빌드나 운영 배포에서 다른 결과가 나올 수 있습니다.

권장 방식은 Spring Boot를 사용하는 프로젝트라면 먼저 Boot가 관리하는 버전을 기준으로 정리하는 것입니다.
이후 꼭 필요한 Jakarta API만 명시하고, API와 구현체가 같은 세대인지 확인해야 합니다.
임의로 Jakarta API 버전만 올리는 방식은 테스트 범위가 넓지 않으면 위험합니다.

4. 소스코드 관점 리스크

javax.* import가 아직 남아 있을 수 있음

Jakarta EE 10을 이미 사용 중이라면 대부분 jakarta.*로 전환되어 있을 가능성이 큽니다. 하지만 오래된 모듈, 테스트 코드, XML 설정, generated source, 사내 공통 모듈에는 javax.*가 남아 있을 수 있습니다.

grep -R "javax\." src/main/java src/main/resources src/test/java
기존 패키지 전환 패키지 확인 영역
javax.servlet.* jakarta.servlet.* Filter, Listener, Interceptor, Servlet API 직접 사용 코드
javax.persistence.* jakarta.persistence.* Entity, Repository, Converter, Auditing
javax.validation.* jakarta.validation.* DTO, Request Body 검증, Custom Validator
javax.annotation.* jakarta.annotation.* @PostConstruct, @PreDestroy
javax.ws.rs.* jakarta.ws.rs.* JAX-RS 기반 연계 코드

JPA 영역은 단순 컴파일보다 데이터 접근 테스트가 중요함

Jakarta Persistence 버전이 올라가면 엔티티 어노테이션이 컴파일되는지만 보면 부족합니다. 실제로는 Hibernate 구현체, Dialect, Query, Lazy Loading, Converter, 날짜 타입, Native Query, Transaction 경계에서 문제가 드러날 수 있습니다.

  • @Entity, @Embeddable, @MappedSuperclass 스캔 여부
  • @Converter 자동 적용 여부
  • JPQL 함수, Native Query, Projection 동작 여부
  • Enum, 날짜/시간 타입, JSON 컬럼 매핑 여부
  • 트랜잭션 테스트와 실제 DB 연결 테스트 결과

Validation은 기동 시점에 바로 터질 수 있음

Validation은 API와 구현체 버전이 맞지 않으면 애플리케이션 기동 중 바로 실패하는 경우가 많습니다. DTO의 @Valid, @Validated, Custom Constraint, Method Validation을 쓰는 프로젝트라면 반드시 확인해야 합니다.

jakarta.validation.NoProviderFoundException
java.lang.ClassNotFoundException: jakarta.validation.Validation
java.lang.NoSuchMethodError

XML 설정과 generated source도 검색 대상에 포함해야 함

Java 코드만 검색하면 놓치는 지점이 있습니다. 오래된 Spring XML 설정, JAXB generated source, WSDL 기반 생성 코드, 테스트 리소스, 사내 공통 jar 안에 javax.* 의존성이 숨어 있을 수 있습니다.

grep -R "javax\." src generated-sources build.gradle pom.xml

현재 Spring 환경별 판단 기준

현재 환경 판단 권장 접근
Spring Boot 2.x 위험 높음 Jakarta EE 11 이전에 Spring Boot 3.x 전환부터 검토
Spring Framework 5.x 위험 높음 Spring Framework 6.x 이상 전환과 Java 17 적용 필요
Spring Boot 3.0~3.2 중간 위험 Boot 관리 버전과 Jakarta API 직접 선언 여부 확인
Spring Boot 3.3 이상 상대적으로 유리 외부 WAS, Hibernate, Validation, SOAP/XML 의존성 위주 점검
Java 8 또는 Java 11 운영 위험 높음 JDK, 빌드, 운영 배포 환경의 Java 17 이상 전환 선행
외부 WAS 배포 주의 필요 WAS의 Jakarta EE 11 지원 수준과 서버 제공 API 확인
SOAP/XML 연계 포함 주의 필요 JAXB, JAX-WS, SAAJ, activation, mail 계열 별도 검증

업그레이드 전 체크리스트

  1. 운영 서버, 빌드 서버, 컨테이너 이미지가 Java 17 이상인지 확인합니다.
  2. Spring Boot 3.x 이상 또는 Spring Framework 6.x 이상 기반인지 확인합니다.
  3. javax.* import가 소스, 리소스, 테스트 코드, 생성 코드에 남아 있는지 검색합니다.
  4. Spring Boot BOM이 관리하는 버전을 무시하고 Jakarta API를 직접 고정한 부분이 있는지 확인합니다.
  5. Tomcat, Jetty, Undertow 또는 외부 WAS가 필요한 Jakarta 스펙을 지원하는지 확인합니다.
  6. Hibernate 버전과 Jakarta Persistence API 버전이 맞는지 확인합니다.
  7. Hibernate Validator, Jakarta Validation API, EL 구현체 조합을 확인합니다.
  8. SOAP, JAXB, JAX-WS, SAAJ, XML Binding 사용 여부를 확인합니다.
  9. 사내 공통 라이브러리나 외부 솔루션 SDK가 javax.* 기반인지 확인합니다.
  10. 단위 테스트뿐 아니라 애플리케이션 기동, DB 접근, 요청 처리, 배포 테스트를 함께 수행합니다.

리스크를 줄이는 현실적인 전환 순서

1단계: Java 17 이상 전환 개발, 빌드, 테스트, 운영 환경의 Java 버전을 먼저 통일합니다. 이 단계에서 class version 오류와 빌드 도구 문제를 먼저 제거합니다.
2단계: Spring Boot 또는 Spring Framework 기준 정리 Spring Boot를 사용한다면 Boot BOM이 관리하는 버전을 우선 기준으로 삼습니다. 직접 선언한 Jakarta API와 구현체 버전을 최소화합니다.
3단계: javax 잔존 의존성 제거 소스코드뿐 아니라 테스트, XML, 생성 코드, 사내 공통 모듈까지 검색해 javax.* 기반 의존성을 제거합니다.
4단계: JPA와 Validation 회귀 테스트 엔티티 매핑, Repository, JPQL, Native Query, DTO 검증, Custom Validator를 중심으로 실제 동작 테스트를 수행합니다.
5단계: SOAP/XML 연계 분리 검증 JAXB, JAX-WS, SAAJ, WSDL 생성 코드가 있다면 별도 모듈로 분리해 의존성과 런타임 충돌을 먼저 확인합니다.

결론

Jakarta EE 10에서 Jakarta EE 11로의 업그레이드는 패키지명 변경보다는 Java 17 기준 상향, 스펙 구성 변경, API와 구현체의 버전 정합성 문제가 핵심입니다. Spring 기존 환경에서는 Jakarta EE 11 자체보다 Spring Boot가 관리하는 의존성 조합과 운영 런타임이 맞는지가 더 중요합니다.

일반적인 Spring Boot 기반 REST API 서버라면 리스크는 중간 수준입니다. 그러나 Spring Boot 2.x, Spring Framework 5.x, Java 8·11 운영 환경, 외부 WAS 배포, SOAP/XML 연계, 오래된 Hibernate 또는 Validator를 사용하는 시스템이라면 리스크가 높습니다.

따라서 Jakarta EE 11 전환은 API 버전만 올리는 작업으로 접근하면 안 됩니다. Java, Spring, WAS, Hibernate, Validation, XML 연계 라이브러리를 하나의 런타임 조합으로 보고 검증해야 안정적으로 전환할 수 있습니다.

반응형