Hi guys, 

Today I recognized easy one tricky part of JIT binding based on *
TypeListeners* and *ChildInjectors* usage. 
Let me explain step by step:

*First*
For every binding *bind(Foo.class).to(FooImpl.class)* one JIT binding will 
be created. Binding for *FooImpl.class* implemented by *
ConstructorBindingImpl.class*. 
As soon as *FooImpl.class* is not explicitly bind, it'll be bind 
just-in-time. As it always happened with final implementations.

*Second*
Guice tried to create JIT binding in parent injector first. If it's not 
possible then in would be created in a child.

Let's review the example. We have some base classes for binding:

   class Dependency {} //just a dependency

    interface Foo {} //interface for binding

    class FooImpl implements Foo {} //base implementation without 
dependencies

    class EnhancedFooImpl implements Foo { //enhanced implementation with 
dependency

        @Inject
        EnhancedFooImpl(Dependency dependency) {
        }

    }

Next, let's make injectors hierarchy: bind nothing in parent and bind our 
classes in child.

      Injector parentInjector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                //nothing here
            }
        });

        parentInjector.createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(Dependency.class);
                
bind(Foo.class).annotatedWith(Names.named("simple")).to(FooImpl.class);
                
bind(Foo.class).annotatedWith(Names.named("enhanced")).to(EnhancedFooImpl.class);
            }
        });

At the child injector initialization time, two just-in-time bindings will 
be created: for *FooImpl.class *and* EnhancedFooImpl.class.*
But due to "JIT parent first strategy" *FooImpl.class *bindings* *will be 
created by parent injector due to both classes have no dependencies at all.
As well as *EnhancedFooImpl.class* will be created by child injector, due 
to dependency on binding from child injector space (*Dependency.class*).

That means, JIT binding will be created by injector which can resolve all 
dependencies by himself. 

*Tricky*
It's tricky because we don't know, what injector actually will build 
implementation instance. Depends on implementation dependencies it can be 
one from all injectors hierarchy. 
And more, what about type listeners defined by child injector?

Let's add type listener for all classes in child injection:

Injector childInjector = parentInjector.createChildInjector(new 
AbstractModule() {
           
            @Override
            protected void configure() {
                bind(Dependency.class);
                
bind(Foo.class).annotatedWith(Names.named("simple")).to(FooImpl.class);
                
bind(Foo.class).annotatedWith(Names.named("enhanced")).to(EnhancedFooImpl.class);

                //bind listener for all injections in this injector
                bindListener(Matchers.any(), new TypeListener() {
                    @Override
                    public <I> void hear(TypeLiteral<I> type, 
TypeEncounter<I> encounter) {
                        encounter.register(new InjectionListener<I>() {
                            @Override
                            public void afterInjection(I injectee) {
                                 //this call was never happened for FooImpl 
creation
                                //but will successfully called for 
EnhancedFooImpl creation 
                            }
                        });
                    }
                });
            }
});

Due to the fact FooImpl.class binding created by parent injector, injection 
listener defined in the child injector would never called. 
Parent injector just doesn't no about some injection listeners in child 
containers :(

So behavior is not obvious. If we have a hierarchy of injector as well as 
hierarchy of type listeners, we can't guarantee what of them will be 
processed and what not. Depends on what level dependencies is enough to 
create JIT binding for implementation class. I think it can create some 
floating issues.  

In addition, to reproduce the same effect, try to inject Injector 
dependency in both implementation classes.  For FooImpl.class it'll be 
parent injector instance. For EnhancedFooImpl.class - child injector 
instance.

I'm not sure, what happened if we will always create JIT binding in an 
injector where binding will be requested. 

P.S. Test attached.

Issue submitted: http://code.google.com/p/google-guice/issues/detail?id=740








 



*
*

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to