이 리포지토리는 Querydsl의 case-when/then + subquery 조합에서
Spring Boot / Hibernate 버전 업그레이드 시 발생한 **Hibernate ORM 회귀 이슈(HHH-18681)**를
재현 가능한 최소 예제(Minimal Reproducible Example) 형태로 정리한 테스트 코드 저장소입니다.
본 저장소는 단순한 이슈 기록이 아니라,
👉 실제 서비스에서 발생한 문제를 재현 → 원인 분석 → Hibernate 업스트림 수정까지 연결한 사례를 담고 있습니다.
-
증상
Hibernate 6.5.3 환경에서SqmSelection.getExpressible()가 null이 되는 케이스 발생
이후getSqmType()호출 시NullPointerException발생 -
트리거
Querydslcase-when-then내부에서 subquery select를 사용하는 특정 패턴 -
결과
Hibernate ORM 측에서 null 가드 처리 패치가 반영되어 이슈 해결
-
Hibernate Jira
https://hibernate.atlassian.net/browse/HHH-18681 -
Hibernate ORM Fix Commit
https://github.com/hibernate/hibernate-orm/commit/36bc892d62d5a33fd5e60f44cebbd31ad026a4b0 -
Hibernate SQM(Semantic Query Model) 참고
https://vladmihalcea.com/hibernate-sqm-semantic-query-model/
해당 문제는 아래 업그레이드 과정에서 확인되었습니다.
- Spring Boot 3.3.0 + Hibernate 6.5.2 → 정상 동작
- Spring Boot 3.3.4 + Hibernate 6.5.3 → NPE 발생
정확한 의존성 버전은 build.gradle 및 테스트 코드에 포함되어 있습니다.
업그레이드 이후 아래 예외가 발생합니다.
Cannot invoke "org.hibernate.query.sqm.SqmExpressible.getSqmType()"
because the return value of
"org.hibernate.query.sqm.tree.select.SqmSelection.getExpressible()" is null
문제의 핵심은 다음 구조입니다.
-
외부 쿼리
select( caseBuilder(...) ) -
내부 조건
caseBuilder.when( subquery.select( caseBuilder(...) ) ... )
즉, case-when-then 내부에 subquery select가 중첩되는 구조에서 Hibernate 내부 SQM 처리 중 오류가 발생합니다.
실제 재현 가능한 쿼리는 테스트 코드로 제공됩니다.
Hibernate 내부 SemanticQueryBuilder#visitSubquery(...) 처리 과정에서
- subquery selection이 1개인 경우
selections.get(0).getExpressible()값이 null일 수 있음- 해당 값에 대해 null 체크 없이
getSqmType()를 호출하면서 NPE 발생
이 리포지토리는 다음 과정을 통해 Hibernate ORM 수정까지 연결되었습니다.
- 실서비스에서 발생한 문제를 Querydsl 기반 최소 재현 테스트로 축소
- Hibernate SQM 생성 흐름을 따라가며 NPE 발생 지점 및 원인 특정
- Hibernate ORM 측에서 null 가드 처리 수정이 반영되어 이슈 해결
수정 내용은 아래 커밋에서 확인할 수 있습니다.
Gradle Wrapper 기준 실행 방법입니다.
./gradlew test --tests "*"
src/test/** 이슈 재현을 위한 최소 테스트 코드
src/main/** 테스트 실행에 필요한 최소 엔티티 및 설정
build.gradle Spring Boot 및 Hibernate 의존성 정의