Error "Missing implementation of resolved method of abstract class " when trying to use covariant returned type

323 Views Asked by At

I have an abstract class with one abstract method:

class A {
    public abstract Element getA();
}

I have several classes that have already implemented this abstract class, and they work fine. For some reasons, I cannot change the method signature of these classes.

class A1 extends A {
    @Override
    public Element getA() {
        // Implementation in A1
    }
}

Now, I'm creating a new class, A2, which extends the abstract class A. However, instead of returning an Element object, I want it to return a list of Element objects.

class A2 extends A {
    @Override
    public List<Element> getA() {
        // Implementation in A2
    }
}

To change the return type of the subclass, I thought about using covariant return types. So, I changed the return type of the abstract class to Object:

class A {
    public abstract Object getA();
}

It compiles without errors and I have no errors when calling A2.getA() but I encounter a runtime error when calling A1.getA(): ""Missing implementation of resolved method 'abstract java.lang.Object getA()' of abstract class A.""

Any advice on how to resolve this issue? Thank you.

1

There are 1 best solutions below

2
Sweeper On

I think you might have forgotten to recompile A1, after you changed A.

There is no return type covariance in the JVM. The JVM doesn't consider Element getA() to implement Object getA(). The Java compiler achieves return type covariance by generating an additional bridge method, with the correct return type.

So after you changed A.getA() to return Object, A2 is compiled to something like this:

class A2 extends A {
    public List<Element> getA() {
        // Implementation in A2
    }

    // This is not valid Java code
    // This is just to illustrate that the compiler generates this additional method in the bytecode
    @Override
    public Object getA() {
        return getA() // this will call the getA that returns List<Element>
    }
}

As far as the JVM is concerned, the Object-returning getA is what implements the abstract method. If you only have the List<Element>-returning getA, the JVM thinks that the abstract method is unimplemented.

Let's see what happens if you forgot to recompile A1. The bytecode for A1 would only contain an Element-returning getA, because when you first compiled A1, the return type matched the abstract method's return type - there was no need to generate a bridge method. But now you changed the abstract method's return type, so the existing getA method in A1 doesn't implement the abstract method anymore!

You should recompile A1 so that a bridge method is generated.