Document the auto-injection workaround for child injectors
diff --git a/org.eclipse.sisu.inject/src/org/eclipse/sisu/inject/DefaultBeanLocator.java b/org.eclipse.sisu.inject/src/org/eclipse/sisu/inject/DefaultBeanLocator.java
index 3206d27..d8b72bf 100644
--- a/org.eclipse.sisu.inject/src/org/eclipse/sisu/inject/DefaultBeanLocator.java
+++ b/org.eclipse.sisu.inject/src/org/eclipse/sisu/inject/DefaultBeanLocator.java
@@ -19,6 +19,7 @@
import org.eclipse.sisu.BeanEntry;
import org.eclipse.sisu.Mediator;
+import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Singleton;
@@ -177,19 +178,41 @@
}
/**
- * Automatically publishes any {@link Injector} that contains a binding to this {@link BeanLocator}.
+ * Automatically publishes any {@link Injector} that contains a binding to this {@link BeanLocator}.<br>
+ * <br>
+ * Relies on Guice's auto-injection, bind the locator with a Provider to disable this feature.
*
* @param injector The injector
*/
@Inject
void autoPublish( final Injector injector )
{
- staticAutoPublish( this, injector );
+ add( new InjectorBindings( injector ) );
}
+ /**
+ * Automatically publishes child {@link Injector}s that inherit a binding to this {@link BeanLocator}.<br>
+ * <br>
+ * Assumes module(s) used to create the child injector request static injection of this class.
+ *
+ * @param childInjector The child injector
+ */
@Inject
- static void staticAutoPublish( final MutableBeanLocator locator, final Injector injector )
+ static void autoPublishChild( final Injector childInjector )
{
- locator.add( new InjectorBindings( injector ) );
+ // Child injectors cannot use the first 'autoPublish' trick because the locator binding is typically inherited
+ // from their parent and the locator instance has already been auto-injected. We workaround this limitation by
+ // requesting static injection of this class in a child module, such as ChildWireModule.
+
+ // When the child injector calls us we introspect the locator binding to see if 'autoPublish' would have been
+ // called in the parent. We avoid checking the provided instance directly since it may have been deliberately
+ // hidden behind a Provider to disable the 'autoPublish' feature, and we need to respect that. Instead we use
+ // the Implementations utility to test whether the binding directly exposes this implementation class.
+
+ final Binding<?> locatorBinding = childInjector.getBinding( MutableBeanLocator.class );
+ if ( DefaultBeanLocator.class.equals( Implementations.find( locatorBinding ) ) )
+ {
+ ( (DefaultBeanLocator) locatorBinding.getProvider().get() ).autoPublish( childInjector );
+ }
}
}
diff --git a/org.eclipse.sisu.inject/src/org/eclipse/sisu/wire/ChildWireModule.java b/org.eclipse.sisu.inject/src/org/eclipse/sisu/wire/ChildWireModule.java
index 5b2df52..44e2495 100644
--- a/org.eclipse.sisu.inject/src/org/eclipse/sisu/wire/ChildWireModule.java
+++ b/org.eclipse.sisu.inject/src/org/eclipse/sisu/wire/ChildWireModule.java
@@ -70,7 +70,7 @@
public void configure( final Binder binder )
{
- // make sure we're added to locator as early as possible
+ // workaround to support 'autoPublish' in child injectors
binder.requestStaticInjection( DefaultBeanLocator.class );
// ignore any inherited bindings/dependencies