5.4 KiB
5.4 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label
| title | source_type | status | related_branches | related_projects | tags | created | status_label | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| error / spotbugs-commons-lang3-bom-downgrade-noclassdef-2026-06-20 | error-note | raw |
|
|
|
2026-06-20 | resolved |
error: spotbugs-commons-lang3-bom-downgrade-noclassdef-2026-06-20
Layer:
raw/errors/— SpotBugs 4.10.2 analysis worker crash caused by the Spring Boot BOM downgrading commons-lang3 on thespotbugstool configuration. The classic "dependency management leaks onto a tool classpath" trap.
Parent / 부모
- raw/branch-notes/feature-static-analysis-quality-contract — D3/D4 SpotBugs + FindSecBugs wiring. Hit while verifying Claim "SpotBugs 6.5.6(core 4.10.2) on Gradle 9.0.0".
증상 / Symptom
- 발생 컨텍스트:
./gradlew spotbugsMain을 처음 실행하자 8/10 모듈에서spotbugsMain FAILED+SpotBugs ended with exit code 4. 버그가 발견된 게 아니라 분석 자체가 죽음 —build/reports/spotbugs/*.xml리포트가 아예 생성 안 됨(crash before report). --console=plain로 보니 root cause:edu.umd.cs.findbugs.ba.AnalysisException: Exception was thrown during analysis Caused by: java.lang.NoClassDefFoundError: org/apache/commons/lang3/Strings Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.Strings at edu.umd.cs.findbugs.ba.vna.ValueNumberFrameModelingVisitor.visitLDC(...)- 재현 가능 여부:
always(Spring Boot dependency-management + SpotBugs 4.10.2 조합에서 항상)
재현 절차 / Reproduction
- Spring Boot
io.spring.dependency-management가 적용된 Gradle 멀티모듈 빌드에서com.github.spotbugs6.5.6 plugin +spotbugs { toolVersion = '4.10.2' }적용. ./gradlew spotbugsMain실행.NoClassDefFoundError: org.apache.commons.lang3.Strings로 분석 worker crash.
조사 단계 / Investigation log
./gradlew :shared-contract:dependencies --configuration spotbugs | grep commons-lang3→org.apache.commons:commons-lang3:3.20.0 -> 3.17.0. SpotBugs 가 요구하는 3.20.0 이 BOM 에 의해 3.17.0 으로 강등됨.- BOM 확인:
spring-boot-dependencies-3.5.15.pom→<commons-lang3.version>3.17.0</commons-lang3.version>. - SpotBugs POM 확인:
spotbugs-4.10.2.pom→commons-lang33.20.0(org.apache.commons.lang3.Strings는 commons-lang3 3.18.0 에서 추가됨 → 3.17.0 엔 없음 → NoClassDefFound). resolutionStrategy.force 'org.apache.commons:commons-lang3:3.20.0'를spotbugs설정에 적용 → 효과 없음. 재확인 시 여전히3.20.0 -> 3.17.0.io.spring.dependency-management가force를 덮어쓴다.- production main 코드에서
org.apache.commons.lang3import 0건 확인 → commons-lang3 는 사실상 SpotBugs 도구 classpath 에만 존재 → 버전 상향의 런타임 영향 없음.
근본 원인 / Root cause
io.spring.dependency-management는 BOM 의 managed version 을 모든 configuration 에 적용한다 — 런타임 classpath 뿐 아니라spotbugs(SpotBugs 분석 worker) 같은 도구 전용 configuration 의 transitive 까지. 그래서 SpotBugs 가 가져오려던 commons-lang3 3.20.0 이 BOM 의 3.17.0 으로 강등되고, 3.17.0 엔 SpotBugs 4.10.2 가 LDC 모델링에서 참조하는org.apache.commons.lang3.Strings가 없어 worker 가 crash 한다.resolutionStrategy.force가 안 먹힌 이유: dependency-management 플러그인이 자체 resolution 액션으로 managed version 을 강제하며, 이게 force 보다 우선한다.
해결 / Resolution
- BOM 이 관리하는 버전 property 자체를 override (Spring 공식 메커니즘):
subprojects 블록에 두면
ext['commons-lang3.version'] = '3.20.0'dependencyManagement가 BOM placeholder 를 3.20.0 으로 해석 →spotbugs설정의 commons-lang3 가 3.20.0 으로 resolve → crash 해소. - 재확인:
dependencies --configuration spotbugs에서commons-lang3:3.20.0(강등 화살표 사라짐),./gradlew spotbugsMain→ 분석 정상 수행(이후 EI/보안 finding 은 reportLevel·exclude 로 별도 처리). - production main 이 commons-lang3 를 안 쓰므로 글로벌 property override 의 실질 영향은 SpotBugs 도구 classpath 한정. 3.17→3.20 은 commons-lang3 3.x 의 backward-compatible minor 상향.
교훈 / Lessons
- Spring dependency-management 는 도구 전용 configuration(spotbugs/checkstyle/errorprone 등)에도 BOM 을 적용한다. 도구가 BOM 보다 최신 transitive 를 요구하면 조용히 강등되어
NoClassDefFoundError/NoSuchMethodError로 런타임에 터진다. resolutionStrategy.force는 dependency-management 를 못 이긴다. 도구 classpath 버전을 고치려면ext['<artifact>.version']로 managed version property 자체를 override 하는 게 정공법.- SpotBugs "exit code 4" + 리포트 부재 = 분석 crash(버그 발견 아님).
--console=plain로AnalysisException/Caused by를 먼저 확인할 것. exit code 1 이 "버그 발견"이고 4 류는 analysis error 신호. - 버전 충돌 디버깅은
gradlew <module>:dependencies --configuration <toolConfig>로 강등 화살표(X -> Y)를 직접 본다.