Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

Sometimes, we may encounter AbstractMethodError at runtime in our application. If we don't know this error well, it might take a while to determine the cause of the problem.

In this tutorial, we'll take a closer look at AbstractMethodError. We'll understand what AbstractMethodError is and when it may happen.

2. Introduction to AbstractMethodError

AbstractMethodError is thrown when an application attempts to call an unimplemented abstract method. 

We know that if there are unimplemented abstract methods, the compiler will complain first. Therefore, the application won't get built at all.

We may ask how we can get this error at runtime?

First, let's have a look at where AbstractMethodError fits into the Java exception hierarchy:

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

As the hierarchy above shows, this error is a subclass of IncompatibleClassChangeError. As its parent class's name implies, AbstractMethodError is usually thrown when incompatibilities exist between compiled classes or JAR files.

Next, let's understand how this error can happen.

3. How This Error May Happen

When we build an application, usually we'll import some libraries to make our work easier.

Let's say, in our application, we include a baeldung-queue library. The baeldung-queue library is a high-level specification library, which contains only one interface:

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

Also, to use the BaeldungQueue interface, we import a BaeldungQueue implementation library: good-queue. The good-queue library also has only one class:

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

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

Now, if both good-queue and baeldung-queue are in the classpath, we may create a BaeldungQueue instance in our application:

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

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

So far, so good.

Someday, we've learned that baeldung-queue released version 2.0 and that it ships with a new method:

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

    int size();
}

We want to use the new size() method in our application. Therefore, we upgrade the baeldung-queue library from 1.0 to 2.0. However, we forget to check if there's a new version of the good-queue library that implements the BaeldungQueue interface changes.

Therefore, we have good-queue 1.0 and baeldung-queue 2.0 in the classpath.

Further, we start using the new method in our application:

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

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

Our code will be compiled without any problem.

However, when the line queue.size() is executed at runtime, an AbstractMethodError will be thrown. This is because the good-queue 1.0 library doesn't implement the method size() in the BaeldungQueue interface.

4. A Real-World Example

Through the simple BaeldungQueue and GoodQueue scenario, we may get the idea when an application may throw AbstractMethodError. 

In this section, we'll see a practical example of the AbstractMethodError.

java.sql.Connection is an important interface in the JDBC API. Since version 1.7, several new methods have been added to the Connection interface, such as getSchema().

The H2 database is a pretty fast open-source SQL database. Since version 1.4.192, it has added the support of the java.sql.Connection.getSchema() method. However, in previous versions, the H2 database hasn't implemented this method yet.

Next, we'll call the java.sql.Connection.getSchema() method from a Java 8 application on an older H2 database version 1.4.191. Let's see what will happen.

Let's create a unit-test class to verify if calling the Connection.getSchema() method will throw 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());
    }
}

If we run the test, it'll pass, confirming that the call to getSchema() throws AbstractMethodError.

5. Conclusion

Sometimes we may see AbstractMethodError at runtime. In this article, we've discussed when the error occurs through examples.

When we upgrade one library of our application, it's always a good practice to check if other dependencies are using the library and consider updating the related dependencies.

On the other hand, once we face AbstractMethodError, with a good understanding of this error, we may solve the problem quickly.

As always, the full source code of the article is available over on GitHub.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
guest
0 Comments
Inline Feedbacks
View all comments