vipx / google-guice

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

Guice.createInjector enforces bindings that become unused by Modules.override #752

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
See test case below. I have a module Foo with an @Provides (buildInt) method, 
and I Modules.override it with another Bar module that redeclares the same 
binding. Therefore, Foo.buildInt is a dead method -- it will never be executed. 
But, when the injector is created, it throws, because that method needs a param 
that is not bound.

The way I came across this issue is that I precisely wanted to override a 
binding in my test because that binding needs a class that is not available on 
these tests.

********************

import com.google.inject.AbstractModule;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.util.Modules;

import junit.framework.TestCase;

import org.junit.Assert;

import java.util.regex.Pattern;

public class OverrideBugTestCase extends TestCase {

  private static final class Foo extends AbstractModule {

    @Override
    protected void configure() {}

    @Provides
    public static Integer buildInt(Pattern foo) {
      return 1;
    }
  }

  private static final class Bar extends AbstractModule {

    @Override
    protected void configure() {}

    @Provides
    public static Integer buildInt() {
      return 2;
    }
  }

  public void testOverride() throws Exception {
    Module foo = new Foo();
    Module bar = Modules.override(foo).with(new Bar());

    // This line is throwing! Even though Bar overrode Foo's Integer binding,
    // Guice still tries to fullfil all bindings needed by Foo.buildInt, which
    // include an unbound Pattern.
    Injector barInjector = Guice.createInjector(bar);

    Assert.assertEquals((Integer)2, barInjector.getInstance(Integer.class));

    try {
      Guice.createInjector(foo).getInstance(Integer.class);
      fail();
    } catch (CreationException e) {}
  }
}

Original issue reported on code.google.com by zorze...@gmail.com on 30 May 2013 at 10:34

GoogleCodeExporter commented 9 years ago
This is happening because of the way @Provides methods are implemented -- we 
call binder.getProvider(Class) for each arg of an @Provides method when doing 
the binding.  Unfortunately there's no built-in way to know "what caused this 
binding", nor is there any graph analysis to know what's dead or not.  So 
unfortunately there's really no way of fixing this until we do full graph 
analysis (and record who "wanted" each binding).

I'm gonna close this one as WontFix 'cause there's really no way I can see this 
happening.. but if you or anyone can dig in and supply a patch that makes this 
happen, awesome.

Original comment by sberlin on 5 Dec 2013 at 11:01