Skip to content

Default methods with @ClientCallable are not published #17098

@javier-godoy

Description

@javier-godoy

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

  1. Run the following example
  2. Click "Call from parent class", observe that the method declared in a superclass is called.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    Status
    🔖 Normal Priority (P2)

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions