users@jersey.java.net

Re: [Jersey] Guice access to Jersey-created objects

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 14 Aug 2009 11:52:17 +0200

Hi Craig,

What is the scope of MyResource? have you bound it to a
Scopes.SINGLETON ? If so i am guessing the MyResource class is
instantiated by Guice outside the scope of the request/response.

You could do the following to bind WebApplication:

         protected void configure() {
             ... bindings for my application objects ...
             bind(WebApplication.class).
                  
toInstance(WebApplicationFactory.createWebApplication()).
                 in(Scopes.SINGLETON);
         }

Of course it needs to be initiated, which i presume you are doing.

Feel free to send me a copy of your project and i can investigate as
well.


For correctly support for injection of UriInfo (etc.) for singletons
we need to have the thread local proxy instance of that class so it
can be reliably injected onto a singleton. An alternative is to inject
Provider<UriInfo> then the existing approach should work.

Like Richard i too have not had any time to follow up on this.

In Guice 2.0 it is not possible to support the following:

     @Path("foo")
     @Encoded
     public class MyResource {

         @Inject
         public class MyResource(@DefaultValue("x") @QueryParam("x")
String x) {
             this.x = x;
         }

         private final String x;

         ...

     }

Guice's approach to custom injections using a TypeListener has
limitations because it means one cannot integrate cleanly with the
parameters associated with @Inject on constructors, fields or methods.

I would like to do something like:

   MetaProvider mp = ...
   bind(QueryParam.class).toMetaProvider(mp);

Where a meta provider has access to the injection type, the
annotations on the type, and the target class. The meta provider is
responsible for creating a provider with the appropriate scope.

I am very very tempted to modify Guice to support this concept.

I don't think this violates anything specific to Guice's approach to
ensuring all things are bound at module initialization (e.g. so one
could output a dependency graph). It does however, make things less
explicit due to the integration of the meta provider. But i would not
expect most developers to create meta providers and instead they would
be created by the much smaller set of framework developers to be
reused. But, i suspect the probability of this concept getting
accepted by the Guice developers may well be close to zero...

Paul.




On Aug 14, 2009, at 6:34 AM, Craig McClanahan wrote:

> Craig McClanahan wrote:
>>
>> Richard Wallace wrote:
>>>
>>> On Thu, Aug 13, 2009 at 11:32 AM, Craig
>>> McClanahan<Craig.McClanahan_at_sun.com> wrote:
>>>
>>>> Furthering my explorations with integrating Jersey and Guice, I'd
>>>> like to be
>>>> able to inject Jersey-provided components into a Guice-
>>>> instantiated service
>>>> class. As a particular example, I have a "transformer" class
>>>> that turns my
>>>> internal data model object into a suitable external representation,
>>>> including some computed URIs. For that, I need to have Guice
>>>> able to inject
>>>> things like the UriInfo object Jersey injects into resource
>>>> classes.
>>>>
>>>> OK, I can bind a Provider<UriInfo> into Guice's injector ... but
>>>> where does
>>>> the implementation of this acquire the UriInfo instance from
>>>> Jersey? Any
>>>> ideas on a strategy to make these kinds of things visible to
>>>> Guice's
>>>> injector?
>>>>
>>>
>>> What I've been doing is allowing Guice to create my WebApplication
>>> instance and injecting that into my own GuiceServletContainer which
>>> overrides the create() method to return the injected WebApplication.
>>> If you do that, then you can do something like what I have here
>>> <http://pastie.org/583188>. It's in Scala, but you should be able
>>> to
>>> get the idea.
>>>
>>> I also talked with Paul once about taking it a bit further. It
>>> requires exposing more of the Jersey services so they could be
>>> injected using Guice 2.0's custom integrations. The biggest
>>> drawback
>>> is that they wouldn't be injectable into the constructor that way,
>>> only on fields and methods. But it would be better than nothing I
>>> figure. Unfortunately, I haven't found the time to follow up on
>>> this.
>>> Maybe you can?
>>>
>>>
>> Thanks for the info ... this will really help. I'll see if I can
>> come up with something we could consider adding to jersey-guice.
>>
> OK, thanks to Rich's head start I've made some progress, but also
> run into a roadblock that is probably due to me misunderstanding
> some Jersey internals. I'm also undoubtedly running into some of
> the same issues Rich saw.
>
> To start with, I'm leveraging the new Guice 2.0 "@Provides"
> annotation to let your Guice module definition supply Provider<XXX>
> instances that operate like factories for some key Jersey internal
> constructs. An excerpt of my module file looks like this (note --
> I'm using Jersey in a Java SE app, not a webapp, so I'm not using
> the servlet related stuff):
>
> public class ServerModule extends AbstractModule {
>
> protected void configure() {
> ... bindings for my application objects ...
> bind(WebApplication.class).
> to(WebApplicationImpl.class).
> in(Scopes.SINGLETON);
> }
>
> @Provides
> public HttpContext httpContext(WebApplication
> webApplication) {
> return webApplication.getThreadLocalHttpContext();
> }
>
> @Provides
> public UriInfo uriInfo(HttpContext httpContext) {
> return httpContext.getUriInfo();
> }
>
> ...
>
> }
>
> To the non-Guice-savvy, what we're doing is declaring:
>
> * If Guice is asked to inject something of type WebApplication,
> create a singleton instance of the Jersey internal class
> WebApplicationImpl and return that. Yes, this is a real hack,
> but dont' know how else to hook into Jersey's own
> component injection machinery.
>
> * If Guice is asked to inject something of type HttpContext,
> go get the WebApplication instance, then call its
> getThreadLocalHttpContext() method, and return its return value.
>
> * If Guice is asked to inject something of type UriInfo,
> go get the HttpContext instance (which will go get the
> WebApplication instance if needed), call getUriInfo(),
> and return its return value.
>
> Now, in theory, I should be able to let Guice inject an UriInfo into
> a resource class (yes, I know Jersey can do that already, but only
> for root resource classes and providers -- I need UriInfo to be
> injectable into any Guice-created instance):
>
> @Path("foo")
> public class MyResource {
>
> @Inject
> public class MyResource(final UriInfo uriInfo) {
> this.uriInfo = uriInfo;
> }
>
> private final UriInfo uriInfo;
>
> ...
>
> }
>
> However, when I trigger a call to this resource, the
> httpContext.getUriInfo() method throws an IllegalStateException
> (ultimately caused by an NPE) which implies that the set() method
> was never set to populate the ThreadLocal instance for this thread.
>
> Phew, that's a lot of Jersey internals ... but can anyone (Paul :-)
> figure out why this is happening? AFAICT I'm in the normal Jersey
> handleRequest() loop, including the execution of a couple of Jersey
> filters, so I would have expected this to work. Note that it also
> fails, but differently, when I try to do field injection instead ...
> it just injects null.
>
>> Craig
>>> Rich
>>>
>>> [1] http://code.google.com/docreader/#p=google-guice&s=google-
>>> guice&t=CustomInjections
>>> [2] http://n2.nabble.com/Enhanced-Guice-Jersey-integration-td3140841.html#a3140841
>>>
>>>
> Craig
>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>>
>>
>