Ошибка конфигурации Guice: реализация не была связана - PullRequest
16 голосов
/ 27 декабря 2010

Я пытаюсь заставить DI с Guice работать, делая (как мне кажется) именно то, что есть в руководстве .

Я не могу объяснить проблему, потому что я действительно не понимаю ее - все кажется очень логичным и должно работать ... но это не так. Итак, я могу только прикрепить код и трассировку стека:

public class Runner {

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new TestModule());
        //next line throws the exception
        JMeterComponent jMeterComponent = 
             injector.getInstance(JMeterComponent.class);
        ....
    }
}

Как видите, я пытаюсь создать экземпляр объекта класса JMeterComponent. Его конструктор (как вы увидите позже) принимает 3 аргумента: все они также должны быть созданы IoC и внедрены.

А вот TestModule с конфигурацией этих 3 аргументов:

public class TestModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Callable.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterTask.class);      
        bind(Processor.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterResultsProcessor.class);
        bind(Renderer.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterResultsWikiRenderer.class);
    }
}

Теперь давайте рассмотрим эти конкретные реализации - JMeterTask, JMeterResultsProcessor и JMeterResultsWikiRenderer (для простоты у всех есть поддельные тела):

public class JMeterTask implements Callable<JMeterRawResults> {

    public JMeterRawResults call() throws Exception {
        return new JMeterRawResults();
    }
}

public class JMeterResultsProcessor implements 
                   Processor<JMeterRawResults, JMeterResults> {

    public JMeterResults process(JMeterRawResults raw) {
        return new JMeterResults();
    }
}

public class JMeterResultsWikiRenderer implements Renderer<JMeterResults> {

    public Map<String, String> render(JMeterResults jMeterResults) {
        Map<String, String> results = Maps.newHashMap();
        ...
        return results;
    }
}

А теперь давайте посмотрим на класс JMeterComponent, конструкция которого является целью всего, что связано с DI, здесь:

public class JMeterComponent extends AbstractComponent<String, String> {

    @Inject
    public JMeterComponent(@Named("JMeter") Callable<String> task, 
                           @Named("JMeter")Processor<String, String> processor, 
                           @Named("JMeter")Renderer<String> renderer) {
        super(task, processor, renderer);
    }
}

А вот и трассировка стека:

Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 1 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating cstat.components.jmeter.JMeterComponent

2) No implementation for stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 2 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating stat.components.jmeter.JMeterComponent

3) No implementation for java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 0 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating stat.components.jmeter.JMeterComponent

Некоторые дополнительные факты:

  1. я использую guice-2.0 (с featured этикетка)
  2. Нет больше аннотации из пакета com.google.inject в любом другом классе в коде
  3. Интерфейсы Processor и Renderer размещены в одном модуле, а их jmeter -реализации (JMeterResultsProcessor и другие) и JMeterComponent класса размещены в другом модуле.

Это почти все, что можно сказать об этом.

Извините за такой длинный пост и спасибо за ваше терпение, чтобы прочитать его до конца.

Есть идеи, почему произошла ошибка и как ее исправить?

1 Ответ

14 голосов
/ 27 декабря 2010

Здесь я вижу несколько проблем.

Во-первых, Callable и Callable<String> различны. Если вы хотите добавить Callable<String> (или Processor<String, String> и т. Д.) В Guice, вам нужно привязать что-то к Callable<String>, а не Callable.

Во-вторых, вы связываете Callable с JMeterTask, который реализует Callable<JMeterRawResults>, но вы вводите Callable<String> в конструктор JMeterComponent (то же самое для Processor и Renderer). Я собираюсь предположить, что JMeterComponent должен быть введен Callable<JMeterRawResults> и т. Д.

В любом случае, вам нужно универсальные привязки, используя TypeLiteral:

bind(new TypeLiteral<Callable<JMeterRawResults>>(){})
    .annotatedWith(Names.named("JMeter"))
    .to(JMeterTask.class);
...