1.

java.lang.NoSuchMethodError の原因と対処

編集
この記事の要点
  • java.lang.NoSuchMethodErrorクラスの定義は見つかったが、特定のメソッドが見つからない
  • 原因: クラスパスに 2 つのバージョンの jar があり、古いバージョンが先に読み込まれる
  • 原因: ライブラリのメジャーバージョン更新で API が変わった
  • 対処: 依存ツリー (mvn dependency:tree) で重複バージョン特定 + exclusion で除外
  • クラスパス全体を ClassLoader.getResources で確認

 

エラーの状況

Exception in thread "main" java.lang.NoSuchMethodError:
'java.lang.String org.apache.commons.lang3.StringUtils.toRootUpperCase(java.lang.String)'
    at com.example.MyClass.process(MyClass.java:42)
    at com.example.Main.main(Main.java:10)

# クラス自体は見つかっているが、そのメソッドだけがない
# → クラスパスのバージョン不整合が大半

原因と対処

原因 1: 同じライブラリの異なるバージョンが共存

# Maven の依存関係を可視化
$ mvn dependency:tree
[INFO] +- org.springframework.boot:spring-boot-starter-web:3.1.0
[INFO] |  +- org.apache.commons:commons-lang3:3.12.0  ← バージョン A
[INFO] +- com.example:legacy-lib:1.0
[INFO]    +- org.apache.commons:commons-lang3:3.5    ← バージョン B (古い)

# → ClassLoader はどちらかを優先するが、古い方が先に来ると新 API メソッドがない

# 詳細表示
$ mvn dependency:tree -Dverbose

# 衝突解消: exclusion で古い方を除外

    com.example
    legacy-lib
    
        
            org.apache.commons
            commons-lang3
        
    

原因 2: API 変更で削除されたメソッドを使用

// 古い API (削除済み)
StringUtils.isBlank(str);  // 残っている
StringUtils.toUpperCase(str);  // 削除されて toRootUpperCase に

// 修正: 新 API を使う or 古いバージョンに戻す
StringUtils.toRootUpperCase(str);

# Maven バージョン固定

    org.apache.commons
    commons-lang3
    3.12.0

原因 3: コンパイル時と実行時で別バージョン

# ビルド時: 新バージョン (新 API 含む) でコンパイル成功
# 実行時: 古いバージョンが classpath にあり、その API がない

# 対処
# 1. 依存ツリー確認
$ mvn dependency:tree | grep commons-lang3

# 2. 全推移依存を固定 (dependencyManagement)

    
        
            org.apache.commons
            commons-lang3
            3.12.0  
        
    

原因 4: Tomcat / Web サーバの shared lib と war の lib 重複

# Tomcat
# $CATALINA_HOME/lib/   ← shared (古いバージョン)
# myapp.war / WEB-INF/lib/  ← アプリ専用 (新バージョン)

# 通常 webapp の lib が優先されるが、ClassLoader 設定次第で逆になる
# context.xml で classLoader を確認

      


# または共有 lib から古い jar を削除

クラスパス確認

// 実行時にロードされた jar のパスを確認
public class ClasspathInspector {
    public static void main(String[] args) {
        ClassLoader cl = ClasspathInspector.class.getClassLoader();
        try {
            // 特定クラスがどこから来ているか
            URL url = cl.getResource("org/apache/commons/lang3/StringUtils.class");
            System.out.println("StringUtils from: " + url);

            // メソッド一覧確認
            Class c = Class.forName("org.apache.commons.lang3.StringUtils");
            for (Method m : c.getMethods()) {
                System.out.println(m);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

# 実行
$ java -cp ... ClasspathInspector
StringUtils from: jar:file:/path/to/commons-lang3-3.5.jar!/org/apache/...

jar 内のクラスを直接確認

# jar 内のクラス一覧
$ jar tf commons-lang3-3.12.0.jar | grep StringUtils
org/apache/commons/lang3/StringUtils.class

# クラスのメソッド一覧
$ unzip -p commons-lang3-3.12.0.jar org/apache/commons/lang3/StringUtils.class > tmp.class
$ javap tmp.class | grep "public static"

# 期待のメソッドがあるか
$ javap tmp.class | grep "toRootUpperCase"
public static java.lang.String toRootUpperCase(java.lang.String);

Gradle での同様の対処

// build.gradle
dependencies {
    implementation("com.example:legacy-lib:1.0") {
        exclude group: "org.apache.commons", module: "commons-lang3"
    }

    implementation "org.apache.commons:commons-lang3:3.12.0"  // 明示
}

// 全体で固定
configurations.all {
    resolutionStrategy {
        force "org.apache.commons:commons-lang3:3.12.0"
    }
}

// 依存ツリー表示
// gradle dependencies

類似エラーとの違い

エラー原因
NoSuchMethodErrorクラスはあるがメソッドがない (このページ)
NoClassDefFoundErrorクラスファイルそのものがない(実行時)
ClassNotFoundExceptionClass.forName 等で動的読込失敗
AbstractMethodError抽象メソッドの未実装
IncompatibleClassChangeError互換性のないクラス変更
UnsupportedClassVersionErrorJava バージョン不整合

調査の流れ

  1. エラーメッセージから対象クラス・メソッドを特定
  2. mvn dependency:tree | grep ... で関係する依存を抽出
  3. 同じ groupId/artifactId で複数バージョンが無いか確認
  4. exclusion または dependencyManagement でバージョン統一
  5. jar の中身javap で確認
  6. クリーンビルド: mvn clean package

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. java.lang.NoSuchMethodError
  2. java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
  3. java.lang.UnsupportedClassVersionError
  4. version less than X.X is not supported.
  5. パッケージ~は存在しません
  6. org.apache.jasper.JasperException: ...The jsp:param action must not be...
  7. java.io.FileNotFoundException: ファイル名 (許可がありません)
  8. java.sql.SQLException: Cannot convert value 'YYYY-MM-DD ...' from column n(YYYY-MM-DD ...) to TIMESTAMP.
  9. 警告: この文字は、エンコーディング[文字コード]にマップできません
  10. java.text.ParseException: Unparseable date
  11. Unsupported major.minor version 52.0
  12. エンティティ" ... "への参照は';'デリミタで終了する必要があります。
  13. java.math.BigDecimal cannot be cast to java.lang.String