-
NoSuchFieldError 원인 - gradle dependencies 문제 파악하기카테고리 없음 2025. 6. 8. 13:18반응형
개요
라이브러리 버전 업그레이드를 진행하던 중 NoSuchFieldError 예외가 발생했습니다.
이 글에서는 NoSuchFieldError가 어떤 상황에서 발생하는지, 실제 발생 사례를 바탕으로 원인 분석 및 해결 과정을 정리해보았습니다.✅ NoSuchFieldError란?
NoSuchFieldError는 Java 애플리케이션 실행 중 특정 클래스에서 존재하지 않는 필드에 접근할 때 발생하는 런타임 에러입니다.
컴파일 시점에는 정상적으로 컴파일되었지만, 런타임 시점에 클래스 간 버전이 맞지 않아 필드가 존재하지 않는 경우 주로 발생합니다.
예를 들어, 어떤 라이브러리의 enum 클래스에 필드가 추가되었지만, 실제 실행 시에는 해당 필드가 없는 구버전의 enum이 로드될 경우 이 에러가 발생할 수 있습니다.문제 상황
맥락에 대해 추가로 설명하자면 boot2, boot3 gradle dependencies가 존재했고 해당 프로젝트는 boot2 기반의 프로젝트였습니다.
코드의 수정의 최소화하며 boot2 -> boot3로 마이그레이션을 수월하게 하기 위해 동일한 패키지명과 이름을 가진 Class들이 2개씩 존재합니다.
이때 의존성을 올리는 과정에서 특정 Class 에서 NoSuchFieldError가 발생했으므로 컴파일러에 의해 의도되지 않은 Class가 로드되었을 가능성을 의심했습니다.
라이브러리 의존성 분석
아래와 같은 명령어로 gradle dependencies 의존성 tree 분석이 가능합니다.
./gradlew :submodule-name:dependencies --configuration runtimeClasspath
jpa-paging 이라는 서브모듈의 의존성 트리 이를 통해 하위 라이브러리가 어떤 의존성을 가지고 있는지 분석할 수 있습니다.
실제 의존성 분석을 수행했을 때 A 라는 enum class가 boot2, boot3 버전 모두가 의존성으로 가져와졌고 boot2 버전의 enum class가 컴파일되었지만, 실제 런타임에서 특정 모듈은 boot3 버전의 enum class를 의존하고 있었습니다.
boot3 버전의 enum class에는 C라는 필드가 존재했지만 boot2 버전의 enum class에는 C라는 필드가 존재하지 않아 실제 런타임에 접근하려다 보니 NoSuchFieldError가 발생하게 되었습니다.
Gradle이 의존성을 선택하는 과정
같은 group:artifacte에서 충돌이 나면 기본적으로 더 높은 버전을 선택합니다.
io.micrometer:micrometer-observation:1.10.7 -> 1.11.0하지만 다음과 같은 경우에는 충돌이 해소되지 않습니다:
io.micrometer.boot2:micrometer-observation io.micrometer.boot3:micrometer-observation위 두 모듈에서 A라는 enum class를 동일하게 가지는 경우는 어떻게 될까요?
이후 JVM 클래스 로딩 과정에서 순서에 따라 하나의 클래스가 선택되며, 이는 우리가 의도한 버전이 아닐 수 있습니다.
해결 방법
해당 케이스는 boot2 프로젝트에서 boot3 모듈을 참조하려다가 발생한 문제여서 boot2 모듈을 의존하도록 변경하면 해결할 수 있습니다.
특정 상황에서는 활용하지 않는 모듈을 의도적으로 exclude 하여 처리할 수 있습니다.
또한 이 경우 런타임에서 감지되기 때문에 테스트코드로 커버리지가 되는 경우라면 빠르게 탐지될 수 있습니다.