[Contribution] Spring Data JPA: Jakarta Persistence 4.0 규격 반영 및 파서 최신화

zion·2026년 1월 15일

최근 Java 생태계는 Jakarta EE 11Jakarta Persistence(JPA) 4.0으로의 전환기에 있습니다. 저는 첫 오픈소스 기여로 Spring Data JPA 프로젝트에 참여하여 차세대 표준 사양을 선제적으로 반영하는 유의미한 경험을 했습니다.


1. 생태계의 변화와 이슈 분석

JPA 4.0 규격의 핵심은 관행적 코드를 표준 API로 대체하여 생산성과 성능을 개선하는 것입니다. Spring Data JPA는 이에 대응하기 위해 관련 이슈들을 생성중이었습니다.

🔍 분석한 주요 이슈 리스트

  • #4141: 신규 정적 쿼리 어노테이션(@StaticQuery) 인프라 확장
  • #4143: 신규 표준 API(getResultCount())를 활용한 페이징 최적화
  • #4144: DTO 프로젝션 리라이팅 로직 개선 및 유연한 매핑 지원
  • #4150: JPA 4.0 문법 변경에 따른 쿼리 파서 업데이트 (My Contribution)

첫 오픈소스 기여다보니, 먼저 가장 부담이 적은 #4150 부터 진행해보기로 했습니다.


2. #4150 해결 과정: CASE 문법 최신화

2.1 문제 정의 (Background)

이전 JPQL 사양에서 CASE 식은 반드시 ELSE 절을 포함해야 했으나, JPA 4.0부터는 ELSE 절이 선택 사항(Optional)으로 변경되었습니다. 생략 시 암묵적으로 NULL을 반환하도록 규격이 완화된 것입니다.

2.2 ANTLR4 문법 수정

Spring Data JPA는 쿼리 해석을 위해 ANTLR4 파서 생성기를 활용합니다. 사용자가 작성한 쿼리가 신규 사양을 준수하는지 판단하도록 Jpql.g4Eql.g4 정의 파일을 수정했습니다.

[Grammar Refactoring]

// 수정 후: (ELSE scalar_expression)? 구문을 통해 ELSE 절을 Optional하게 변경
general_case_expression
    : CASE when_clause (when_clause)* (ELSE scalar_expression)? END ;

simple_case_expression
    : CASE case_operand simple_when_clause (simple_when_clause)* (ELSE scalar_expression)? END ;

ELSE 구문을 ()? 기호로 그룹화하여 처리함으로써, 파싱 단계에서의 Syntax Error를 제거하고 표준 규격을 수용했습니다.


3. Merged, Polished, and Backported

해당 Pull Request는 리뷰를 거쳐 메인 저장소에 병합(Merge)되었습니다.

그리고 메인테이너에 의해 백포트(Backport) 되었습니다.

"Jakarta Persistence 4.0은 아직 정식 릴리즈 전인데, 이전 버전(Backport)에 들어가도 정말 괜찮은 걸까?"


4. 표준, 구현체, 그리고 추상화의 관계

자바 데이터 접근 계층은 표준, 구현체, 추상화 라이브러리의 상호작용을 통해 발전합니다.

구분프로젝트역할
표준 (Spec)Jakarta Persistence 4.0공통 명세 및 문법 규칙 정의
구현 (Impl)Hibernate 6.x / 7.0명세에 따른 실제 쿼리 실행 엔진
추상화 (Lib)Spring Data JPA고수준 인터페이스 및 가이드 제공

구현체 선행 (Running Code First): 표준 문서 확정 전이라도 Hibernate이 기능을 지원한다면, 프레임워크는 이를 수용해 생태계 정합성을 맞춥니다.

4.1 구현체(Hibernate)의 선행 지원 확인

분석 결과, 구현체인 Hibernate는 이미 2021년 6.0(Alpha) 설계 당시부터 SQL 표준 준수를 위해 CASE 문의 ELSE를 선택 사항으로 정의해 두었습니다.

[Hibernate HqlParser.g4 소스코드]

// Hibernate 6.0+ 에서는 이미 ELSE 절에 '?'(Optional)가 적용되어 있음
simpleCaseList
    : CASE expressionOrPredicate simpleCaseWhen+ caseOtherwise? END ;

4.2 기여의 가치: 기술적 단절(Mismatch) 해소

이번 기여의 핵심은 라이브러리 간의 규격 동기화에 있습니다.

  • 현상: 엔진(Hibernate)은 이미 ELSE가 없는 쿼리를 실행할 수 있었으나, 상위 계층인 Spring Data JPA 파서의 구식 규격이 이를 가로막고 있었습니다.
  • 해결: Spring Data JPA의 파서를 최신 표준에 맞춰 업데이트함으로써, 하부 엔진의 기능을 상위 프레임워크 수준에서 정상적으로 사용할 수 있도록 수정했습니다.

5. 정리를 마치며: 공급자의 시각을 얻다

이번 기여를 통해 얻은 핵심 수확은 라이브러리를 '공급자적 시각'에서 바라보게 된 점입니다.

  • 선순환 구조의 이해: 우리가 당연시했던 기능들이 표준과 구현체의 긴밀한 상호작용 결과물임을 확인했습니다. 특히 백포트를 통해 생태계의 속도를 맞추는 오픈소스의 운영 방식을 체감했습니다.
  • 기술적 공백의 보완: 익숙한 도구의 내부 구조를 파헤치며 이론적 공백을 채웠습니다. 낮은 난이도의 이슈로 시작한 점은 아쉽지만, 도구의 본질을 분석하고 기여로 연결한 경험 자체가 큰 성장이었습니다.

이번 경험을 발판 삼아, 앞으로는 프레임워크의 설계 철학까지 깊이 파고드는 기여자로 꾸준히 성장하겠습니다.

🔗 관련 Pull Request
Support optional ELSE in CASE expressions (JPA 4.0) #4150

profile
be_zion

0개의 댓글