users@jersey.java.net

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

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Fri, 14 Aug 2009 09:47:56 -0700

Paul Sandoz wrote:
> 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.
I'm not explicitly binding the root resource class used in my example
... GuiceComponentProviderFactory is finding and registering them. But
for my general purpose needs, I need to be able to bind things like
UriInfo into custom scopes.
>
> 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);
> }
You actually have to leave off the in(Scopes.SINGLETON) for this ...
toInstance() returns void. At any rate, this didn't change the behavior.
>
> 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.
>
Isn't that basically what the @Provides uriInfo() method does? I'll try
it with an explicit provider class and see if that makes any difference.
> 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...
>
I suspect you might be right.

I'm also going to play a little with GuiceyFruit and see if James got
anywhere on this sort of thing. But I suspect he's not focused on
integration with frameworks.
> Paul.
>
Craig

>
>
>
> 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
>>>>
>>>>
>>>
>>
>