users@jersey.java.net

Re: [Jersey] Injection only at the top level resource?

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Wed, 07 Jan 2009 15:40:15 +0100

On Jan 7, 2009, at 3:22 PM, Gerard M. Davison wrote:

>
> Paul,
>
> Thanks, that seem reasonable. At least in the case I am looking at I
> need to pass some parameters to the created resource object. I guess
> that the middle two are the most useful in my case. (@Resource
> doesn't appear to be attachable to a method parameter otherwise I
> would quite happily be using that)
>

Hmm... it should work in conjunction the InjectableProvider you
created and registered. The reason is that all the other injection
support is implemented the same way (e.g. @Context for injection of
ResourceContext in the example in my previous email). If not then it
is a bug i need to fix.


> Perhaps a suggested enhancement would be to extend ResourceContext
> with either:
>
> 1. Allow args constructors
>
> <T> T getResource(Class<T> c, Object... args)
>

Yes, i was pondering about that as well. Note that it is also possible
to have annotated parameters on constructors. See the section "Rules
of Injection" in the following document:

   http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features


> 2. Allow post creation injection
>
> <T> T inject(T input)
>

To correctly inject Jersey needs to know the life-cycle (e.g. per
request or singleton) of what it is injecting stuff on to.

Of course things would be a little different if there was an IoC
framework standardized when we specified JAX-RS :-) which is what we
really need.


> But I could understand you not wanting to go down this route and
> wait until the JEE integration is finished.
>

I think what you suggest above is independent of the EE integration,
since management and injection will never be performed on instances
returned from sub-locator resources.

Paul.

> Again thanks for your answer,
>
> Gerard
>
>
>
> Paul Sandoz wrote:
>> Hi Gerard,
>>
>> Injection does not occur on instances returned by the application,
>> namely in sub-resource locators. Jersey does not manage instances
>> returned from sub-resource locators, it does not know what the life-
>> cycle is, so it cannot do postCreate/preDestroy or inject.
>>
>> There are a number of things you can do:
>>
>> - return the Class of the resource;
>>
>> - use ResourceContext
>>
>> @Path("subresource")
>> public ProxiedSubResource getSubResource(@Context ResourceContext
>> rc) {
>> return rc.getResource(ProxiedSubResource.class);
>> }
>>
>> - use an IoC framework integrated with Jersey like Spring to
>> obtain an instance.
>>
>> - inject on method parameters.
>>
>> All of the above, except the last one, are currently non-standard
>> w.r.t. JAX-RS.
>>
>> JAX-RS and Jersey are not yet EE compliant. We are working on that
>> for JAX-RS 1.1 which will align with Java EE 6 and then we will
>> implement support for injection of EE stuff on resource classes in
>> Jersey/GF. I view the InjectableProvider as an intermediate
>> solution until we have full EE 6 support in Jersey/GF.
>>
>> Paul.
>>
>> On Jan 7, 2009, at 11:44 AM, Gerard M. Davison wrote:
>>
>>>
>>> Hi,
>>>
>>> I am fairly new to Jersey so apologies in advance if this is a
>>> stupid question. I am trying to write a simple InjectableProvider
>>> so that I get can @Resource injections working. My
>>> ServletContainer that registers this looks something like the
>>> following. (Note I expect there to be some glaring mistakes in the
>>> implementation here; but it seems to work for my little example
>>> application).
>>>
>>> public class ServletAdapter extends ServletContainer {
>>> @Override
>>> protected void configure(ServletConfig servletConfig,
>>> ResourceConfig rc,
>>> WebApplication wa) {
>>> super.configure(servletConfig, rc, wa);
>>>
>>>
>>> rc.getSingletons().add(new InjectableProvider<Resource,
>>> Type>() {
>>>
>>> public ComponentScope getScope() {
>>> return ComponentScope.Singleton;
>>> }
>>>
>>> public Injectable<Object>
>>> getInjectable(ComponentContext ic,
>>> Resource r,
>>> Type c) {
>>>
>>> final Holder value = new Holder();
>>>
>>> try {
>>> Context ctx = new InitialContext();
>>>
>>> // Look up a data source
>>> try
>>> {
>>> value.value = ctx.lookup(r.name());
>>> }
>>> catch (NamingException ex) {
>>>
>>> value.value = ctx.lookup("java:comp/env/"
>>> + r.name());
>>> }
>>> } catch (Exception ex) {
>>>
>>> ex.printStackTrace(); }
>>>
>>> return new Injectable<Object>() {
>>>
>>> public Object getValue() {
>>> return value.value;
>>> }
>>> };
>>> }
>>> });
>>> }
>>> }
>>>
>>>
>>> This works find when injecting resource at the root of a resource
>>> path but not for any sub resources. So the field in Parent is
>>> populated but the field in Child is not.
>>>
>>> @Path("/")
>>> public class Parent
>>> {
>>> @Resource(name="....")
>>> DataSource ds;
>>>
>>>
>>> @Path("/child/")
>>> public Child getChild()
>>> { ... }
>>> }
>>>
>>> public class Child
>>> {
>>> @Resource(name="....")
>>> DataSource ds;
>>>
>>> ... }
>>>
>>> My question is is this a bug or a feature? Certainly to my naive
>>> eye I would have expected the resource injection to happen for
>>> each level, certainly I can pass in the resource via constructors
>>> but this is going to unnecessarily complicate my code design.
>>> Particularly if the resource in question is only going to be used
>>> by one leaf in the tree.
>>>
>>> Finally is there a reason that the basic JSR-250 annotations such
>>> as @Resource at not supported by default?
>>>
>>> Thanks for any pointers,
>>>
>>> Gerard
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>>
>