Description of the bug
Default methods that are annotated with @ClientCallable are not published, because AbstractServerHandlers recurses the declared methods upon the class hierarchy (thus failing to detect any default method declared in an interface).
|
Stream.of(clazz.getDeclaredMethods()).filter( |
|
method -> hasAnnotation(method, getHandlerAnnotationFqn())) |
|
.forEach(method -> addHandlerMethod(method, methods)); |
|
collectHandlerMethods(clazz.getSuperclass(), methods); |
Expected behavior
methodFromInterface should be published to $server because it's a public method in TestViewWithCallables and such method is annotated with @ClientCallable. The method is not overriden in the class, thus the annotation from the interface remains.
Indeed TestViewWithCallables.class.getMethod("callFromInterface").isAnnotationPresent(ClientCallable.class) returns true.
Minimal reproducible example
- Run the following example
- Click "Call from parent class", observe that the method declared in a superclass is called.
- Click "Call from interface", observe that the method declared in an interface is not called.
abstract class AbstractViewWithCallable extends Div {
@ClientCallable
private void methodFromParentClass() {
System.out.println("Called from parent class");
}
}
interface InterfaceWithCallable {
@ClientCallable
default void methodFromInterface() {
System.out.println("Called from interface");
}
}
@Route
public class TestViewWithCallables extends AbstractViewWithCallable implements InterfaceWithCallable {
public TestViewWithCallables() {
add(new Button("Call from parent class", ev -> {
getElement().executeJs("this.$server.methodFromParentClass()");
}));
add(new Button("Call from interface", ev -> {
getElement().executeJs("this.$server.methodFromInterface()");
}));
}
}
As a workaround, override the default method in the view class, and annotate it again with @ClientCallable
@Override
@ClientCallable
public void methodFromInterface() {
InterfaceWithCallable.super.methodFromInterface();
}
Versions
- Vaadin / Flow version: 24.1.1
Description of the bug
Default methods that are annotated with
@ClientCallableare not published, becauseAbstractServerHandlersrecurses the declared methods upon the class hierarchy (thus failing to detect any default method declared in an interface).flow/flow-server/src/main/java/com/vaadin/flow/internal/nodefeature/AbstractServerHandlers.java
Lines 158 to 161 in 913a1e5
Expected behavior
methodFromInterfaceshould be published to$serverbecause it's a public method inTestViewWithCallablesand such method is annotated with@ClientCallable. The method is not overriden in the class, thus the annotation from the interface remains.Indeed
TestViewWithCallables.class.getMethod("callFromInterface").isAnnotationPresent(ClientCallable.class)returnstrue.Minimal reproducible example
As a workaround, override the default method in the view class, and annotate it again with
@ClientCallableVersions