Skip to content

Method invokers #460

@arjantijms

Description

@arjantijms

(copied from CDI.Next doc, as there was no issue yet to track this)

Currently CDI does not have a concept of a bean method that can be executed from another bean with parameter binding.
Such a concept is used in other specs, such as JAX-RS, where resource methods are executed at runtime with the need to bind their parameters, and provide the support for interceptors and other CDI features.
The CDI spec should add API for such a feature, so other specs do not need to define a custom solution.

The following should be possible:

  • Obtain a reference to executable method with all metadata, including annotations on method and on fields
  • Execute an executable method on a bean instance
  • Obtain executable method metadata in interceptors (to analyze annotations using reflection-less approach)
  • Create a parameter binder, that would support a specific annotation on a parameter (basically a parameter qualifier)

Pseudocode:

Let’s consider the following bean:

@RequestScoped
@Path("/greet")
public class Resource {
   @GET
   String helloWorld(@HeaderParam("HEADER") String header) {
   }
}
@Qualifier
@Target(ElementType.PARAMETER)
public @interface HeaderParam {
   String value();
}

Now we could create a parameter binder:

@Singleton
@Binder(HeaderParam.class)
public class HeaderParamBinder implements ParamBinder {
   // HttpHeaders is a request scoped bean
   private final HttpHeaders headers;
   private final Converter converter;

   @Inject
   HeaderParamBinder(HttpHeaders headers, Converter converter) {
       this.headers = headers;
       this.converter = converter;
   }

   public <T> T bind(HeaderParam annotation, GenericType<T> type) {
       return converter.convert(headers.getRequestHeader(annotation.value()), type);
   }
}

And the execution of this method would be something like:

@MethodHandler(Path.class)
public class JaxRsExecutor implements ExecMethodHandler<Object, Object> {
   private final ParameterBinder binder;
   private final Container container;
  
   @Inject
   JaxRsExecutor(ArgumentBinder binder) {
       this.binder = binder;
   }

   @Override
   public void processMethod(ExecutableMethod<Object, Object> method) {
       // process registration with web server
   }
  
   private void executeMethod(ExecutableMethod<Object, Object> method) {
       // start request scope
       Object beanInstance = container.select(method.getDeclaringType()).get();
       method.invoke(beanInstance, binder.bind(method));
   }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    spec-featureAn issue requesting an addition specification

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions