If you have a child injector and ask the parent injector a value for a binding defined in the child, you get an "It was already configured on one or more child injectors" error.
It would be better to say "No implementation for ... was bound, although it is configured in a child injector".
Here's a sample code:
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class GuiceBug {
public static void main(String[] args) {
Injector i1 = Guice.createInjector();
Injector i2 = i1.createChildInjector(
new AbstractModule() {
@Override
protected void configure() {
bind(IStuff.class).to(Stuff.class);
}
});
i1.getInstance(IStuff.class);
}
static interface IStuff {}
static class Stuff implements IStuff {}
}
Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
1) Unable to create binding for org.enercoop.test.GuiceBug$IStuff. It was already configured on one or more child injectors or private modules
bound at org.enercoop.test.GuiceBug$1.configure(GuiceBug.java:15)
If it was in a PrivateModule, did you forget to expose the binding?
while locating org.enercoop.test.GuiceBug$IStuff
1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at GuiceBug.main(GuiceBug.java:18)
What makes you say it's misleading? The error is correct: you can't get the binding from the parent because it's bound in the child. Leading with "no implementation was bound" seems more misleading, because one _was_ bound.. just in a different place.
Saying "it was already configured" make me think it was configured twice which is not the case. It does not suggest it was configured in another place. If you configure a binding in both parent and child you also get "A binding to ... was already configured at ...".
If you have one apple and someone takes that apple, when you try to get it the result is "You can't, someone already took the apple". The apple wasn't taken twice. When you try to get it (the first time for you, the second time in total), you're told it was already taken.
This is the same. You try to create a binding on the parent (by way of getting a binding that doesn't exist on it yet) and the result is you're told you can't create the binding because it was already configured on a child injector.
I get your point, but I still find this confusing, because "Elements of the child injector are not visible to its parent". So if I want something from the parent which is not defined in it, it fails just because of that, not because of anything defined or not in the children.
That's incorrect. It fails precisely because it's defined in the child. If it was just not defined in the parent, then the binding would be created at runtime as a just-in-time binding. It can't create the just-in-time binding, though, because the binding already exists in the child, and Guice doesn't allow bindings in both the parent & child.
I can't help but think @laurentmartelli was right about this error.
bind
call, I get this errorbind
call, I get "No implementation for
... was bound
"How can I have too many bindings, then remove one binding, and then not have enough?
fyi I also found this extremely confusing.
NB child injectors are extremely confusing. We try hard to avoid using them internally.
Yeah the error message is confusing. However now googling the error will give this discussion and allow people to resolve it despite the wording. Thanks @laurentmartelli!
+
1 on this
It was confusing for me as well, googling this discussion turned out the fastest way to find the actual cause, so the message could just as well have a link to this discussion.
Most helpful comment
I can't help but think @laurentmartelli was right about this error.
bind
call, I get this errorbind
call, I get "No implementation for
...was bound
"How can I have too many bindings, then remove one binding, and then not have enough?