1. 概要

アプリケーションの実行時にAbstractMethodErrorが発生する場合があります。 このエラーがよくわからない場合は、問題の原因を特定するのに時間がかかることがあります。

このチュートリアルでは、AbstractMethodErrorを詳しく見ていきます。 AbstractMethodError とは何か、いつ発生する可能性があるかを理解します。

2. AbstractMethodErrorの概要

AbstractMethodError は、アプリケーションが実装されていない抽象メソッドを呼び出そうとするとスローされます。 

実装されていない抽象メソッドがある場合、コンパイラが最初に文句を言うことはわかっています。 したがって、アプリケーションはまったくビルドされません。

実行時にこのエラーを取得するにはどうすればよいですか?

まず、AbstractMethodErrorがJava例外階層のどこに適合するかを見てみましょう。

java.lang.Object
|_java.lang.Throwable
  |_java.lang.Error
    |_java.lang.LinkageError
      |_java.lang.IncompatibleClassChangeError
        |_java.lang.AbstractMethodError

上記の階層が示すように、このエラーはIncompatibleClassChangeErrorのサブクラスです。 親クラスの名前が示すように、 AbstractMethodErrorは通常、コンパイルされたクラスまたはJARファイル間に非互換性が存在する場合にスローされます。

次に、このエラーがどのように発生するかを理解しましょう。

3. このエラーがどのように発生するか

アプリケーションをビルドするときは、通常、作業を簡単にするためにいくつかのライブラリをインポートします。

たとえば、アプリケーションにbaeldung-queueライブラリが含まれているとします。 baeldung-queue ライブラリは、次の1つのインターフェイスのみを含む高レベルの仕様ライブラリです。

public interface BaeldungQueue {
    void enqueue(Object o);
    Object dequeue();
}

また、 BaeldungQueue インターフェイスを使用するには、BaeldungQueue実装ライブラリgood-queueをインポートします。 good-queueライブラリにもクラスは1つだけです。

public class GoodQueue implements BaeldungQueue {
    @Override
    public void enqueue(Object o) {
       //implementation 
    }

    @Override
    public Object dequeue() {
        //implementation 
    }
}

ここで、good-queuebaeldung-queueの両方がクラスパスにある場合、アプリケーションにBaeldungQueueインスタンスを作成できます。

public class Application {
    BaeldungQueue queue = new GoodQueue();

    public void someMethod(Object element) {
        queue.enqueue(element);
        // ...
        queue.dequeue();
        // ...
    }
}

ここまでは順調ですね。

いつの日か、baeldung-queueがバージョン2.0をリリースし、新しいメソッドが付属していることを知りました。

public interface BaeldungQueue {
    void enqueue(Object o);
    Object dequeue();

    int size();
}

このアプリケーションでは、新しい size()メソッドを使用します。 したがって、baeldung-queueライブラリを1.0から2.0にアップグレードします。 ただし、BaeldungQueueインターフェイスの変更を実装するgood-queueライブラリの新しいバージョンがあるかどうかを確認するのを忘れています。

したがって、クラスパスには good-queue1.0baeldung-queue2.0があります。

さらに、アプリケーションで新しいメソッドの使用を開始します。

public class Application {
    BaeldungQueue queue = new GoodQueue();

    public void someMethod(Object element) {
        // ...
        int size = queue.size(); //<-- AbstractMethodError will be thrown
        // ...
    }
}

私たちのコードは問題なくコンパイルされます。

ただし、行 queue.size()が実行時に実行されると、AbstractMethodErrorがスローされます。 これは、 good-queue 1.0ライブラリがBaeldungQueueインターフェイスのメソッドsize()を実装していないためです。

4. 実際の例

シンプルで BaeldungQueue GoodQueue シナリオでは、アプリケーションがいつスローするかがわかる場合があります AbstractMethodError。 

このセクションでは、AbstractMethodErrorの実際の例を示します。

java.sql.Connection は、JDBCAPIの重要なインターフェースです。 バージョン1.7以降、 getSchema()。など、いくつかの新しいメソッドがConnectionインターフェイスに追加されました。

H2データベースは、非常に高速なオープンソースのSQLデータベースです。 バージョン1.4.192以降、 java.sql.Connection.getSchema()メソッドのサポートが追加されました。 ただし、以前のバージョンでは、H2データベースはまだこのメソッドを実装していません。

次に、古いH2データベースバージョン1.4.191のJava8アプリケーションからjava.sql.Connection.getSchema()メソッドを呼び出します。 何が起こるか見てみましょう。

Connection.getSchema()メソッドを呼び出すと AbstractMethodError がスローされるかどうかを確認するために、単体テストクラスを作成しましょう。

class AbstractMethodErrorUnitTest {
    private static final String url = "jdbc:h2:mem:A-DATABASE;INIT=CREATE SCHEMA IF NOT EXISTS myschema";
    private static final String username = "sa";

    @Test
    void givenOldH2Database_whenCallgetSchemaMethod_thenThrowAbstractMethodError() throws SQLException {
        Connection conn = DriverManager.getConnection(url, username, "");
        assertNotNull(conn);
        Assertions.assertThrows(AbstractMethodError.class, () -> conn.getSchema());
    }
}

テストを実行すると合格し、 getSchema()の呼び出しがAbstractMethodErrorをスローすることを確認します。

5. 結論

実行時にAbstractMethodErrorが表示される場合があります。 この記事では、エラーが発生するタイミングについて例を挙げて説明しました。

アプリケーションの1つのライブラリをアップグレードするときは、他の依存関係がライブラリを使用しているかどうかを確認し、関連する依存関係の更新を検討することをお勧めします。

一方、 AbstractMethodError に直面すると、このエラーを十分に理解すれば、問題を迅速に解決できる可能性があります。

いつものように、記事の完全なソースコードは、GitHubから入手できます。