How to override some bindings in a child injector?

3,724 views
Skip to first unread message

progm...@gmail.com

unread,
Oct 3, 2011, 1:45:45 AM10/3/11
to google-guice
Hello! I need to override some bindings in a child injector. I can't
use Modules.overrides because I don't know about list of modules which
had been used during parent injector creating. For example:

public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule()
{
@Override
protected void configure() {
bind(IContainer.class).to(ContainerImpl.class);

bind(IChild.class).to(ChildImpl.class);
}
});

IContainer container = injector.getInstance(IContainer.class);

container.createNewChild();
}


interface IChild {}

class ChildImpl implements IChild {
@Inject
ChildImpl(Container parentContainer) {
// parentContainer should pointed on container object which
had created this object! It should no be a new instance of
ContainerImpl class!
}
}

interface IContainer {
IChild createNewChild();
}

class ContainerImpl implements IContainer {
private final Injector injector;

@Inject
ContainerImpl(Injector injector) {
this.injector = injector;
}

public IChild createNewChild() {
Injector childInjector = injector.createChildInjector(new
AbstractModule() {
@Override
protected void configure() {
bind(IContainer.class).to(ContainerImpl.class); // Not
works!
}
});

return childInjector.getInstance(IChild.class);
}
}




Aleksey V. Katorgin

unread,
Oct 3, 2011, 2:15:00 AM10/3/11
to google-guice
Please correct my error in code example in my post. I wrote:

bind(IContainer.class).to(ContainerImpl.class); // Not works!

but need:

bind(IContainer.class).to(ContainerImpl.this); // Not works!

Thanks!

Thomas Broyer

unread,
Oct 3, 2011, 4:13:03 AM10/3/11
to google...@googlegroups.com
How about trying to use AssistedInject instead?

progm...@gmail.com

unread,
Oct 3, 2011, 4:33:46 AM10/3/11
to google...@googlegroups.com
Thanks for replay, Thomas.

Child object can contain subchilds objects too. And I want the parent container reference can be provided to subchilds via injection too.

Sam Berlin

unread,
Oct 3, 2011, 8:50:20 AM10/3/11
to google...@googlegroups.com
Child injectors cannot override bindings from a parent injector, by design.  Allowing this kind of behavior would create some very surprising (and nearly impossible to debug) scenarios.

What is it that you're trying to achieve?

sam

On Mon, Oct 3, 2011 at 4:33 AM, progm...@gmail.com <progm...@gmail.com> wrote:
Thanks for replay, Thomas.

Child object can contain subchilds objects too. And I want the parent container reference can be provided to subchilds via injection too.

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/aFpWQ6K8DuAJ.

To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.

progm...@gmail.com

unread,
Oct 3, 2011, 8:58:29 AM10/3/11
to google...@googlegroups.com
I have a hierarchic objects structure that creates dynamically and I want the parent objects of this hierarchy can be injected into children constructors via Guice.

progm...@gmail.com

unread,
Oct 3, 2011, 9:07:07 AM10/3/11
to google...@googlegroups.com
First step: I create container object by help a Guice which has a module with container implementation class.
Second step: inside the container I create child injector in which I want replace the container object implementation binding to instance of this container.
Third step: I create child object via child injector so from now I can inject the parent object to child object constructor.


In other words I want to replace container implementation binding in child injector, for example:

bind(Container.class).to(ContainerImpl.class) 

to concrete instance of created container (inside the container object):

bind(Container.class).toInstance(this)

and use this new binding for creating child objects.



I have small workaround for this, but it now works for Provider bindings:

    public static <T, I extends T> Injector createInjectorWithBindReplacement(final Injector sourceInjector,
                                                                       final Class<T> clazz, final I instance) {
        return Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(clazz).toInstance(instance);

                Map<Key<?>, Binding<?>> srcInjectorBindings = sourceInjector.getAllBindings();

                for (Map.Entry<Key<?>, Binding<?>> srcKeyBindingEntry : srcInjectorBindings.entrySet()) {

                    Key<?> srcKey = srcKeyBindingEntry.getKey();

                    if (srcKey.equals(Key.get(Injector.class))
                            || srcKey.equals(Key.get(java.util.logging.Logger.class))) {
                        continue;
                    }

                    if (srcKey.equals(Key.get(clazz))) {
                        continue;
                    }

                    System.out.println(srcKeyBindingEntry); // todo remove

                    srcKeyBindingEntry.getValue().applyTo(binder());
                }
            }
        });
    }


progm...@gmail.com

unread,
Oct 3, 2011, 9:08:57 AM10/3/11
to google...@googlegroups.com
Sry, NOT WORKS for Providers

Sam Berlin

unread,
Oct 3, 2011, 9:16:16 AM10/3/11
to google...@googlegroups.com
The reason overriding a binding in a child injector isn't supported is because it can lead a developer towards writing code that can work in either a parent & child injector, but have different behavior in each.  This can lead to very surprising scenarios, because of just-in-time (JIT) bindings and the way they interact with parent/child injectors.

Recycling an old reply to our internal guice list (about private modules, but they're implemented with child injectors & have the same behavior) --
The design is such that just-in-time bindings are always created in the parent injector first.  If it fails in the parent injector, then it's created in the child injector (the private modules) .  In your scenario, because one particular private module specifies the drink, the other private modules will always have their drinks local to them, because the parent will refuse to create a JIT binding if any of its children have a binding for that key.

It's done this way because there's no way of knowing to know if the binding should live in the parent or child, and choosing based on who asks for it first (the parent or the child) is more a race condition than anything else.  Consider if you really wanted drink to be a shared singleton such that even the parent wanted to participate in the drinking but relied on the JIT to do this.  If the child were to ask for the drink first and it was created in the child injector, then the parent would never be able to drink at all.

sam

On Mon, Oct 3, 2011 at 9:08 AM, progm...@gmail.com <progm...@gmail.com> wrote:
Sry, NOT WORKS for Providers

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/j4ZGzu5KfIAJ.
Reply all
Reply to author
Forward
0 new messages