vipx / google-guice

Automatically exported from code.google.com/p/google-guice
Apache License 2.0
0 stars 0 forks source link

bindInterceptor in child injector #461

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I have two tests here, identical except for the dependencies of the
concrete type.

Note that "BadFoo" is not getting the method interceptors applied, but
"GoodFoo" is.  Apparently this is because GoodFoo has dependencies which
are themselves defined in the child injector, but BadFoo does not.

This might be related to issue#390.
-----------------

public void testNoArgConstructor() throws Exception
{
  Injector parent = Guice.createInjector();
  Injector child = parent.createChildInjector( 
    new TestModule( BadFoo.class ) );

  TestObject o = child.getInstance( TestObject.class );
  assertEquals( "intercepted", o.item.call() );
}

public void testConstructorWithDependencies() throws Exception
{
  Injector parent = Guice.createInjector();
  Injector child = parent.createChildInjector(
    new TestModule( GoodFoo.class ) );

  TestObject o = child.getInstance( TestObject.class );
  assertEquals( "intercepted", o.item.call() );
}

public static class TestModule extends AbstractModule
{
  private final Class<? extends Callable<String>> concreteType;
  public TestModule( Class<? extends Callable<String>> concreteType ) {
    this.concreteType = concreteType;
  }

  @Override
  protected void configure()
  {
    bind( TestObject.class );
    bind( new TypeLiteral<Callable<String>>(){} ).to( concreteType );
    bindInterceptor( Matchers.any(), Matchers.any(), new InterceptMe() );
  }

  @Provides
  public String whoIsChasingYou()
  {
    return "inigo montoya";
  }
}

public static class TestObject {
  @Inject
  protected Callable<String> item;
}

public static class BadFoo implements Callable<String> {
  @Inject
  public BadFoo() {}
  public String call() { return "default"; }
}

public static class GoodFoo implements Callable<String> {
  @Inject
  public GoodFoo( String ignore ) {}
  public String call() { return "default"; }
}

public static class InterceptMe implements MethodInterceptor {
  @Override
  public Object invoke( MethodInvocation call ) throws Throwable {
    return "intercepted";
  }
}

Original issue reported on code.google.com by gil...@gmail.com on 20 Jan 2010 at 11:32

GoogleCodeExporter commented 9 years ago
You need to explicitly bind the concrete type in the child module. Add this 
line to 
TestModule, and things will work as you intend:
  bind(concreteType);

This requirement is in the documentation for createChildInjector():
  "Just-in-time bindings created for child injectors will be created in an ancestor 
injector whenever possible. This allows for scoped instances to be shared 
between 
injectors. Use explicit bindings to prevent bindings from being shared with the 
parent injector."

Original comment by limpbizkit on 21 Jan 2010 at 8:49

GoogleCodeExporter commented 9 years ago
OK.  "bind(concreteType)" is a fine work around.  This feels leaky abstraction, 
but the workaround is clear.

I guess I didn't understand that the target of a binding is a just-in-time 
binding in the same way an unbound 
type is.  I guess this is what Bob Lee meant in issue#342 about JIT bindings 
from the user's perspective.  Oh 
well, fair enough.

I wonder if it's still very much a bug that, for the purpose of deciding if a 
class can be created in a parent 
injector,  the interceptors are not considered dependencies in the same way 
things marked with @Inject are?

Thanks Jessie.

Original comment by gil...@gmail.com on 21 Jan 2010 at 5:31