Skip to content

@AllowInert is not propagated to the instrumented bridge method for @LegacyClientCallable #31

@javier-godoy

Description

@javier-godoy

When a method is annotated with both @LegacyClientCallable and @AllowInert, the instrumented bridge method generated by ClassInstrumentationUtil is only annotated with @ClientCallable. The @AllowInert annotation is silently dropped, so the method cannot be called from the client side when the component is inert, contrary to the developer's intent.

Steps to reproduce

public class MyComponent extends Component {
    @LegacyClientCallable
    @AllowInert
    public void handleCallback(JsonValue value) { ... }
}

Instrument the class with JsonMigrationHelper. Reflectively inspect the handleCallback method on the instrumented subclass: @AllowInert is absent from the bridge method.

Expected behaviour

The bridge method carries both @ClientCallable and @AllowInert.

Actual behaviour

The bridge method carries only @ClientCallable.

Root cause

generateMethodOverride in ClassInstrumentationUtil (line 432) unconditionally emits exactly one annotation and never iterates the original method's annotations:

mv.visitAnnotation(Type.getDescriptor(ClientCallable.class), true);

The fix is to scan the original method's annotations after emitting @ClientCallable and re-emit any @AllowInert found, using a class-name comparison to avoid a compile-time dependency on Vaadin 24+:

mv.visitAnnotation(Type.getDescriptor(ClientCallable.class), true).visitEnd();

for (Annotation annotation : method.getAnnotations()) {
    if ("com.vaadin.flow.component.internal.AllowInert"
            .equals(annotation.annotationType().getName())) {
        mv.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd();
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions