dev@jersey.java.net

Re: [Jersey] GuiceComponentProviderFactory seems to ignore Guice Scope for object bound in parent injector

From: Jae Lee <jlee119_at_gmail.com>
Date: Wed, 13 May 2009 00:44:30 +0100

Hi Paul,

I made some attempts on writing some tests for the scenarios that I
described...

Through some debugging the tests that I've written, I've learned a bit more
about Jersey, where for explicit Guice bound object it's mapping

   1. Scopes.SINGLETON ----> ComponentScope.Singleton
   2. Scopes.NO_SCOPE ----> ComponentScope.PerRequest

It was a bit of surprise that (if my test is written correct... I need some
confirmation on whether I'm building ResourceFactory in the right way and
also the way I'm modeling multiple Resource instantiation in the same
request and different requests is reasonable)

   1. for objects in child injector; Scopes.NO_SCOPE, it seems to generate
   new instance in the same request
   2. for objects in parent injector; Scopes.NO_SCOPE, it seems to generate
   same instance in the same request
   3. for objects in child/parent injector; Scopes.SINGLETON, it seems to
   generate same instance all the time

Regards
J

On Mon, May 11, 2009 at 1:49 PM, Paul Sandoz <Paul.Sandoz_at_sun.com> wrote:

> Hi Jae,
> BTW i am still finding my away around with Guice and am by no means an
> expert so providing use cases like this is very valuable.
>
> I notice that from here:
>
>
> http://code.google.com/p/google-guice/source/browse/trunk/src/com/google/inject/Injector.java
>
> /**
> * Returns all explicit bindings.
> *
> * <p>The returned map does not include bindings inherited from a {_at_link
> #getParent() parent
> * injector}, should one exist. The returned map is guaranteed to iterate
> (for example, with
> * its {_at_link java.util.Map#entrySet()} iterator) in the order of
> insertion. In other words,
> * the order in which bindings appear in user Modules.
> *
> * <p>This method is part of the Guice SPI and is intended for use by
> tools and extensions.
> */
> Map<Key<?>, Binding<?>> getBindings();
>
>
> So the Injector.getBindings does not return bindings from the parent
> injector (if any). It was not the intention to ignore bindings of the
> parent.
>
> So IIUC the fix would be to traverse up the injector hierarchy, to find the
> injector that contains an explicit binding for the class:
>
> private Injector findInjector(Key<?> key) {
> Injector i = injector;
> while (i != null) {
> if (i.getBindings().containsKey(key))
> return i;
>
> i = i.getParent();
> }
> return null;
> }
>
> public IoCComponentProvider getComponentProvider(ComponentContext cc,
> Class clazz) {
> if (LOGGER.isLoggable(Level.FINE)) {
> LOGGER.fine("getComponentProvider(" + clazz.getName() + ")");
> }
>
> Key<?> key = Key.get(clazz);
> Injector i = findInjector(key);
> // If there is no explicit binding
> if (i == null) {
> // If an @Inject is explicitly declared
> if (!isInjectPresent(clazz)) {
> return null;
> }
> ...
>
>
> Would that work for you?
>
> Would it be possible to provide a simple test case that represents your
> use-case and i can add that as a unit test.
>
> Paul.
>
>
> On May 10, 2009, at 2:23 PM, Jae Lee wrote:
>
> Hi all,
> I've got a newbie question really...
>
> From brief look through GuiceComponentProviderFactory source code
> (1.1.0.ea), it looks like if you built GuiceComponentProviderFactory with an
> Injector Guice Scope is ignored for an object explicitly bound by its parent
> Injector... is that an intended behaviour?
>
> In my current project, we've got an Application and many Components
> underneath. Component being loosely related resources, defines an
> independent context. It is achieved by having a child Injector for each
> Component under an Application.
>
> Naturally we would have common class/object bound in Injector in
> Application (a bit like application scope) and component specific
> class/object bound in child Injector in Component (a bit like component
> scope)
>
> It looks like GuiceComponentProviderFactory uses
> GuiceInstantiatedComponentProvider which ignores Guice Scope, for any
> explicitly bound class in parent Injector. Which is bit of problem when it
> comes to Singleton scoped class.
>
> Injector.getBinding(key) does return binding from parent Injector if
> possible then fall back to Just In Time binding with Scopes.NO_SCOPE.
>
> Given that even for Just In Time binding, there's a scope (NO_SCOPE) that
> can be mapped to Jersey, is it possible to use GuiceManagedComponentProvider
> all the time? Would that makes it functionally different from current
> implementation? Benefit would be that then it can support Singleton Guice
> object in parent Injector properly.
>
> regards
> J
>
>
>