2015-09-18 2 views
3

Вот мой код:Почему Guice не связывается с промежуточной зависимостью?

// Groovy 
interface MyMapper { 
    Buzz toBuzz(Fizz fizz); 
} 

class MyMapperImpl implements MyMapper { 
    @Named("SIMPLE_FOOBAR") 
    Foobar foobar; 

    MyMapperImpl(Foobar foobar) { 
     super(); 
     this.foobar = foobar; 
    } 

    @Override 
    Buzz toBuzz(Fizz fizz) { 
     // ...etc. 
    } 
} 

class Whistlefeather { 
    MyMapper mapper; 

    Whistlefeather(MyMapper mapper) { 
     super(); 

     this.mapper = mapper; 
    } 

    void doSomething(Fink fink) { 
     Fizz fizz = getSomehow(fink); 
     Buzz buzz = mapper.toBuzz(fizz); 

     // Do something with 'buzz'... 
    } 
} 

class ApplicationMain { 
    Whistlefeather whistlefeather; 

    @Inject 
    ApplicationMain(Whistlefeather whistlefeather) { 
     super(); 

     this.whistlefeather = whistlefeather; 
    } 

    static void main(String[] args) { 
     Injector injector = Guice.createInjector(new ApplicationModule()); 
     ApplicationMain appMain = injector.getInstance(ApplicationMain); 
     appMain.run(); 
    } 

    void run() { 
     whistlefeather.doSomething(new Fink()); 
    } 
} 

Вот мой Guice модуль:

class ApplicationModule extends AbstractModule { 
    @Override 
    protected void configure() { 
     // I have to name the Foobars because in reality there will be 
     // *many* of them, each configured slightly different. 
     bind(Foobar.class).annotatedWith(Names.named("SIMPLE_FOOBAR")) 
      .toInstance(new Foobar(true, true, false, 103, "yee haw")); 

     bind(MyMapper.class).to(MyMapperImpl); 
    } 
} 

Вот мое исключение:

Could not find a suitable constructor in com.me.myapp.MyMapperImpl. 
Classes must have either one (and only one) constructor annotated 
with @Inject or a zero-argument constructor that is not private. 

Мои понимания было то, что мне нужно только для аннотирования конструкторов с @Inject если я буду напрямую звонить им через метод Injector#getInstance(...). Поскольку я делаю это с помощью ApplicationMain, который содержит ссылку на Whistlefeather, в котором содержится ссылка на MyMapper, я не думал, что мне придется комментировать конструктор MyMapperImpl.

Любые идеи относительно того, где я буду здесь здесь?

ответ

5

Чтобы Guice создал любой объект, он должен знать, какой конструктор использовать. Это верно вплоть до Object Graph.

Рассмотрим следующий код:

public interface Something { } 
public class SomethingImpl implements Something { 
    private final String data; 

    public SomethingImpl(String data) { 
    this.data = data; 
    } 

    public SomethingImpl(Integer data) { 
    this.data = data.toString(); 
    } 
} 
public class AnotherClass { 
    private final Something something; 

    @Inject 
    public AnotherClass(Something something) { 
    this.something = something; 
    } 
} 
public class MyModule extends AbstractModule { 
    @Override 
    protected void configure() { 
    bind(Something.class).to(SomethingImpl.class); 
    bind(String.class).toInstance("Hello!"); 
    bind(Integer.class).toInstance(50); 
    } 
} 

В этом случае, как Guice должен знать, какой конструктор использовать в SomethingImpl? Если бы вы были автором Guice, как бы вы его написали?

Очевидно, вы не можете ответ, потому что это невозможно. Должен быть какой-то механизм, чтобы сказать Guice, какой конструктор использовать, независимо от того, вызван он или нет его Injector.getInstance() или нет; поэтому вы должны аннотировать хотя бы один конструктор. Guice будет использовать конструктор без аргументов по умолчанию, если он указан, но если его нет, Guice не знает, что делать.

Смежные вопросы