users@jersey.java.net

Re: [Jersey] Enhanced Guice-Jersey integration

From: Richard Wallace <rwallace1979_at_gmail.com>
Date: Thu, 25 Jun 2009 12:46:41 -0700

On Thu, Jun 25, 2009 at 1:40 AM, Paul Sandoz<Paul.Sandoz_at_sun.com> wrote:
>
> On Jun 24, 2009, at 2:25 AM, Richard Wallace wrote:
>
>> On Tue, Jun 23, 2009 at 2:14 AM, Paul Sandoz<Paul.Sandoz_at_sun.com> wrote:
>>>
>>> Hi Richard,
>>>
>>> We could modify WebApplication to have a method getProviders().
>>>
>>> Jersey holds information on all the injectable stuff registered (whether
>>> it
>>> be Jersey or JAX-RS specific, or added by the developer). I am wondering
>>> if
>>> it might be best to expose that. In fact that will be the best way to
>>> expose
>>> the @*Param stuff because there is logic in the Injectable instances to
>>> extract stuff from the HttpContext, e.g. see the source in jersey-server
>>> for:
>>>
>>>  com.sun.jersey.server.impl.model.parameter.QueryParamInjectableProvider
>>>
>>> I wonder if we could write code to loop through the injectables that are
>>> registered and explicitly bind them?
>>>
>>>  bind(c).to(cProvider).in(scope);
>>>
>>> At least for those within the singleton scope.
>>>
>>
>> That would definitely work.
>>
>
> After 1.1.1-ea i will have a look at cleaning up the internal implementation
> for expose it to the SPI.
>

Along with the OSGi changes? You're a busy busy guy! But I really
appreciate it, thanks!

>
>>>
>>> It is a shame we cannot use the Matchers.any() for bind:
>>>
>>>
>>>  bind(Matchers.any()).annotatedWith(QueryParam.class).to(qProvider).in(RequestScoped.class)
>>>
>>> ?
>>
>> No, the other problem with that, AFAIK, is that the annotations you
>> bind with have to be annotated with the Guice BindingAnnotation.
>>
>
> Ah, yes.
>
>
>>>
>>> I cannot recall if James got this to work with GuiceyFruit. (Also not
>>> that
>>> the Guice/Jersey integration supports injection onto fields of
>>> Guice-managed
>>> classes).
>>>
>>>
>>> The following:
>>>
>>>   @Provides public UriInfo uriInfo(HttpContext httpContext) {
>>>       return httpContext.getUriInfo();
>>>   }
>>>
>>> returns a request-scoped value, the httpContext is thread local but the
>>> values it returns are not. Is that an issue?
>>>
>>
>> Some of the values it returns are request-scoped, such as the request
>> and response.  I would have used some globally accessible value for
>> UriInfo but couldn't find a way to access it.  That would certainly be
>> a far better alternative.
>
> I was not questioning the use of HttpContext. I think you did the right
> thing. I was wondering about how we declare what the scope is to Guice.
>

By default, everything in Guice is considered "scopeless" unless you
give it a scope. Which basically means that the Provider is consulted
everytime you need to inject a value. For this case, I think that's
what we want.

>
>>
>>
>>> Jersey registers thread local proxies for UriInfo etc to be injected onto
>>> singletons and the actual instances to be injected on per-request
>>> resources.
>>> It tries to optimize as much as possible to avoid the repeated use of
>>> thread
>>> locals when the request is available directly.
>>>
>>
>> That's the advantage of being directly wired into the request
>> processing lifecycle.  With a proper hook we could create a child
>> injector to be used for that request, and that would avoid any of the
>> thread local stuff.  But that's the only way I can think of.  Even
>> using the Guice servlet integration and putting that stuff in the
>> RequestScope would mean storing it in the ServletRequest attributes.
>> But the ServletRequest itself is accessed via a thread local.  So, no
>> matter what you have to have at least a single thread local.
>
> OK. I guess there is no way of saying: "this thing is compatible with the
> @RequestScope, but you do not need to manage it".
>

No, and that really wouldn't mean anything anyways. Guice scopes are
purely about when the Provider is consulted for a value to be used for
injection. I think what we want is just the default, which is "no
scope".

>
>>  I'm not
>> sure if that or creating a child injector would be more performant.
>> Probably depends on the number of objects that are going to be created
>> in a single request that will be injected with request data.
>>
>
> OK. I guess we should get things functional first and worry about
> performance later.
>

Ya, I agree.

> I am quite willing to use and make changes where required to GuiceyFruit
> (with James permission, and with the view to getting such changes back into
> Guice). Is that something you are interested in? that way we might be able
> to support the constructor parameters, and get better support for injection
> of the @*Param.
>
> For example, see the Limitations section here;
>
>  http://code.google.com/p/guiceyfruit/wiki/Annotations
>
>  Currently due to the Guice restriction that @Inject must be used on all
> constructors we can only use
>  injection annotations like @Resource and @Autowired on fields and methods;
> not on constructors.
>
>  We may try patch Guice to remove this restriction in future versions of
> GuiceyFruit
>

I saw that and that's why I pointed out it wouldn't work on
constructor or method injection. I'd definitely be interested in
adding support for this to GuiceyFruit and eventually getting the
changes merged back into Guice itself. I wonder how much James has
already looked into this and if he has any ideas.

Rich