Hi,
I just committed stuff that replaces the existing Injectable approach
with a new package called:
com.sun.jersey.spi.inject
I recommend if you are depending on the old approach not to upgrade just
yet as there might still be changes to those interfaces as further
implementation work occurs.
Basically the existing behavior is supported using the new interface. To
add to support for an injectable on a field as before one does the
following:
class MyInjectableProvider implements
InjectableProvider<MyAnnotation, Type, SingletonInjectable<Object>> {
public SingletonInjectable<Object> getInjectable(
InjectableContext ic, MyAnnotation a, Type c) {
if (c is not a supported type)
return null;
final Object o = ... // get the injectable value
return new SingletonInjectable<Object>() {
public Object getValue() {
return o;
}
}
}
}
(Note that Type, and SingletonInjectable are currently the only types
supported for the 2 and third generic type arguments).
At the end of the email is code for the injection of an
EntityManagerFactory with the @PersistenceUnit works.
Next steps:
- plug in parameter-based injectable providers for parameters of
methods/constructors. Thus moving fully over to the unified model.
Only use thread local proxied injectable providers for non-per-request
resources (performance enhancement).
- allow use of @Provider on InjectableProvider. Thus it is no longer
necessary to register via WebApplication. They become components that
can also be managed by an IoC.
- injection meta class to perform injection to avoid use of reflection
each time, a performance enhancement for per-request resources.
- support injection onto fields of per-request resources for per-request
injectable providers.
- support bean setter methods.
A nice consequence: when completed one should be able to add their own
injectable providers for @*Param that go beyond the existing rules of
311 e.g. using joda date time class. Another possible nice consequence:
it could make the support of @FormParam easier :-)
Paul.
wa.addInjectable(new InjectableProvider<PersistenceUnit, Type,
SingletonInjectable>() {
public SingletonInjectable<EntityManagerFactory>
getInjectable(InjectableContext ic, PersistenceUnit pu, Type c) {
if (!c.equals(EntityManagerFactory.class))
return null;
// TODO localize error message
if (!persistenceUnits.containsKey(pu.unitName()))
throw new ContainerException("Persistence unit '"+
pu.unitName()+
"' is not configured as a servlet parameter
in web.xml");
String jndiName = persistenceUnits.get(pu.unitName());
ThreadLocalNamedInvoker<EntityManagerFactory> emfHandler =
new
ThreadLocalNamedInvoker<EntityManagerFactory>(jndiName);
final EntityManagerFactory emf = (EntityManagerFactory)
Proxy.newProxyInstance(
EntityManagerFactory.class.getClassLoader(),
new Class[] {EntityManagerFactory.class },
emfHandler);
return new SingletonInjectable<EntityManagerFactory>() {
public EntityManagerFactory getValue() {
return emf;
}
};
}
});
Paul Sandoz wrote:
> 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