users@jersey.java.net

Unifying injection

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 19 May 2008 17:23:32 +0200

Hi,

Currently the injection support is split between the Injectable abstract
class and hard-wired support for the @*Param.

There are a number of use-cases we need to support:

- pluggable injection on parameters of constructors and methods,
   so then we can support the inclusion of IoC based parameters as
   part of the signature.

- 311 requirement of using injection with setter methods, for example:

   @QueryParam("name")
   public void setName(String name) { ... }

   @Context
   public void setUriInfo(UriInfo name) { ... }

- 311 requirement for injection of @*Param on fields of per-request
   resources.

- as a consequence this should make it easier to optimize the creation
   and injection on per-request resources as well as the method
   invocation on resource methods and sub-resource locators of
   per-request or non-per-request resources (with the long term view of
   injectables providing generated byte code "snippets")

Such cases force the demand for unifying the pluggable injection model,
and abstracting it from where stuff gets injected (field, parameter, or
setter method) and constraining what can be injected based on the
life-cycle of the resource, the life-cycle of what is injected and the
context of injection.


More technical details follow....

I am proposing that there be an InjectableProvider that provides
Injectable instances per the context, annotation and type (same pattern
as the ResourceProvider concept). Concrete Injectable instances can be
either one of SingletonInjectable, where the injectable value is
independent of the request, or PerRequestInjectable, where the
injectable value is dependent on the request (see below for proposed
classes, i am sure they will change when implementation starts).

This approach is a little different to the current mechanism of
Injectable, instances of which are essentially singletons. Instead
Jersey will analyze the fields, setter, constructor/method parameters of
resource classes and loop through the InjectableProvider's until it
finds one that returns null. So essentially Jersey will create an
artifact of the runtime model to perform specific injection for a
resource class (this should speed up per-request life-cycle injection
for fields and setters) (such artifacts are already created for
constructor and method invocation).

For the longer term i envisage a ByteCodeGenerator interface that could
be implemented by Injectable implementations. To generate the snippet of
byte code related to obtaining the injectable value. In general this
would also extend to the actual invocation of resource methods.

Paul.

  // Provide an injectable instance for a particular
  // annotation and type.
  interface InjectableProvider<A extends Annotation,
         I extends Injectable> {
     enum Context { Field, Parameter, Setter };

     A getAnnotation();

     // return null if not supported
     I<A> getInjectable(Context c, A a, Type t)
  }

  abstract class Injectable<A extends Annotation> {
     public Injectable(A a, Type t) { ... }
  }

  class SingletonInjectable<A extends Annotation, T>
       extends Injectable {

     public abstract T getValue();
  }

  class PerRequestInjectable<A extends Annotation, T>
       extends Injectable {

     public abstract T getValue(HttpContext context);
  }

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109