Ошибка: java.lang.AbstractMethodError при вызове универсального метода, реализующего интерфейс
Я пытаюсь использовать javassist для программного создания и компиляции класса (во время выполнения), который реализует интерфейс.
Я получаю следующую ошибку всякий раз, когда я вызываю экземпляр этого динамического класса:
java.lang.AbstractMethodError: FooImpl.test()Ljava/lang/Object;
Вот мой интерфейс
public class FooBarInterface<T> {
public T getEntity();
}
Вот образец сущности
public class FooEntity {
@Override
public String toString() {
return "Hello, Foo!";
}
}
Вот как я программно реализую интерфейс
public void test() {
ClassPool classPool = ClassPool.getDefault();
CtClass testInterface = classPool.get(FooBarInterface.class.getName());
CtClass fooImpl = classPool.makeClass("FooImpl");
fooImpl.addInterface(testInterface);
CtMethod testMethod = CtNewMethod.make(
"public com.test.FooEntity getEntity(){" +
"return new com.test.FooEntity();" +
"}",
canImpl
);
fooImpl.addMethod(testMethod);
fooImpl.writeFile();
TestInterface<FooEntity> test =
(TestInterface<FooEntity>) fooImpl.toClass().newInstance();
System.out.println(test.getEntity());
}
Если я изменил тип возвращаемого значения реализованного метода на Object, то я не получу сообщение об ошибке, например:
CtMethod testMethod = CtNewMethod.make(
"public Object getEntity(){" +
"return new com.test.FooEntity();" +
"}",
canImpl
);
Тогда я успешно получаю hello, Foo!
, Я в порядке с изменением типа возвращаемого значения на Object, но я хотел бы понять больше, почему возвращение с типом Foo производит AbstractMethodError
,
3 ответа
Внутри JVM методы с разными типами возврата различны. После стирания типа, FooBarEntity.getEntity()
имеет тип возврата Object
, Вызовы через интерфейс будут искать специально метод с типом возврата Object
следовательно, почему ваша реализация должна вернуть Object
,
Обычно ваш Java-компилятор создает методы моста, которые пересылают результат конкретного метода как стертый тип, но, очевидно, Javassist не делает этого за вас (я не использовал Javassist, поэтому я не уверен).
Для получения дополнительной информации о том, как методы моста используются для реализации стирания типов, см. Официальный раздел Учебники Java по методам моста.
У меня была такая же ошибка. У меня был базовый класс, в котором я объявил новый абстрактный метод. Я реализовал этот метод в других классах, которые его потребляли. Теперь при отладке я получаю ошибку абстрактного метода, как только я нажимаю на реализацию метода.
Решение: я полагал, что базовый класс использовался и другими артефактами, и я не переопределил вновь созданный абстрактный метод в этих артефактах. Так как я никогда не собираю их, поскольку я не изменял их, JVM никогда не выдает ошибку времени компиляции, но возникает исключение времени выполнения. При реализации метода в других артефактах я смог избавиться от исключения. В основном, в моем случае все дочерние классы не имели реализации абстрактного метода базового класса.
Когда у вас есть параметризованный параметр или возвращаемый тип, компилятор Java компилирует его так, как если бы он был Object, и синтезирует метод моста с параметризованной сигнатурой, которая вызывает другую. Или, возможно, наоборот. Вы только синтезировали один из них, а не оба.