xiaodududu / google-guice

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

AssistedInject fails with optimized providers in edge cases #632

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Normally, FactoryProvider2 would expect that the parent inject is constructing 
'Object3' here, but Guice will recognize it has a dependency on something only 
the child can provide, so will fall back into adding the JIT binding for 
'Object3'  in the child injector.  The rest of the FactoryProvider2 didn't 
expect this, and fails (visible with the "this should never happen").

A fix may be to inspect the JIT bindings of the child injector for dependencies 
that could invalidate the optimization.  (If any child JIT binding exists, it 
has to be because it depends on an @Assisted param, which means they're tainted 
too, and all classes need to be analyzed for Provider<..> dependencies on them, 
and they need to be analyzed for Provider<..> dependencies of other tainted 
things.)

Test-code
-----

public class GuiceErrorTest extends TestCase {

  @Inject
  Object1Factory object1Factory;

  public void testInjectionFailure() throws Exception  {

    Guice.createInjector(new Module()).injectMembers(this);
    object1Factory.create(1).run();
  }

  public static class Module extends AbstractModule {
    @Override
    protected void configure() {
      install(new FactoryModuleBuilder().build(Object1Factory.class));
      install(new FactoryModuleBuilder().build(Object2Factory.class));
    }
  }

  public interface Object1Factory {
    Object1 create(@Assisted("a1") long a);
  }

  public static class Object1{

    private final Object2Factory object2Factory;
    private final long a;

    @Inject
    public Object1(@Assisted("a1") long a, Object2Factory object2Factory) {
      this.a = a;
      this.object2Factory = object2Factory;
    }

    public void run() throws Exception  {
      object2Factory.create(a).run();        
    }    
  }

  public interface Object2Factory {
    Object2 create(@Assisted("a1") long a);
  }
  public static class Object2 {
    Provider<Object3> object3Provider;

    @Inject
    public Object2(Provider<Object3> object3Provider) {
      this.object3Provider = object3Provider;
    }

    public void run() {
      object3Provider.get(); // This will fail with an IllegalStateException
    }
  }

  /*
   * Instantiation of this Object fails at runtime:
   * Cannot use optimized @Assisted provider outside the scope of the constructor.
   */
  public static class Object3 {

    @Inject
    public Object3(@Assisted("a1") long a) {
    }
  }
}

Original issue reported on code.google.com by sberlin on 24 May 2011 at 3:40