Post

jenv local 11 해도 Java 17 바이트코드가 나오는 이유

build.gradle에 자바 버전이 없으면 빌드 JVM이 바이트코드 버전이 된다 — jenv shim과 toolchain의 차이

jenv local 11 해도 Java 17 바이트코드가 나오는 이유

서버에서 UnsupportedClassVersionError: class file version 61.0 ... up to 55.0 가 떠서 jenv local 11로 바꾸고 재빌드해도 같은 에러. 캐시인 줄 알았는데 빌드 JVM 자체가 안 바뀐 거였다.

핵심: build.gradle에 자바 버전이 없으면 빌드 JVM = 바이트코드 버전

sourceCompatibility/targetCompatibility/toolchain 중 하나도 없으면 Gradle은 그냥 “빌드를 실행하는 JVM 버전”으로 컴파일한다. jenv를 바꿔도 빌드 JVM이 그대로면 바이트코드도 그대로.

진단: ./gradlew -v 의 JVM 라인을 본다

1
2
./gradlew -v
# JVM: 17.0.17 (Eclipse Adoptium 17.0.17+10)  ← 여기가 11이 아니면 끝

jenv local 11./gradlew 래퍼 스크립트에 적용 안 되는 경우가 흔하다. 래퍼가 새 셸을 띄우면서 JAVA_HOME을 우선 읽기 때문. shim 통과 여부는 항상 gradlew -v로 확인할 것.

부수적으로 의심할 곳:

  • ~/.gradle/gradle.propertiesorg.gradle.java.home (있으면 jenv 무시됨)
  • Gradle 데몬 (./gradlew --status → 옛 JVM으로 떠 있으면 --stop)

클래스 버전 → JDK 매핑 + 매직바이트로 검증

Javaclass file versionhex (마지막 2바이트)
85200 34
115500 37
176100 3D

JAR 내부 .class 매직바이트로 직접 확인:

1
2
3
4
5
unzip -p build/libs/myapp-1.0-SNAPSHOT.jar \
  BOOT-INF/classes/com/example/app/MyApplication.class \
  | od -An -t x1 -N 8
# ca fe ba be 00 00 00 37   ← Java 11
# ca fe ba be 00 00 00 3d   ← Java 17

영구 픽스: 빌드 JVM 무관하게 타겟 못박기

build.gradle:

1
2
3
4
java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

또는 toolchain (Gradle이 알아서 11 JDK 받아옴):

1
2
3
4
5
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(11)
    }
}

이러면 빌드 머신/CI/누구의 jenv 상태든 무조건 Java 11 호환 바이트코드만 나간다. “jenv로 맞춰주세요” 같은 운영 의존성을 없애는 게 핵심.

에러 메시지 읽는 법

1
2
3
class file version 61.0 ... up to 55.0
                    ↑              ↑
                빌드 JDK(17)   런타임 JDK(11)

앞 숫자가 빌드 쪽, 뒷 숫자가 런타임 쪽. 둘 중 어디를 맞춰야 할지 헷갈리지 말 것.

This post is licensed under CC BY 4.0 by the author.