Guice AssistedInject не будет внедрять фабрику

Я пытаюсь использовать Guice 3.0 AssistedInject, и он не создает экземпляр фабрики.

Код SSCCE:

Родительский класс

public class ParentClass() {
  @Inject private MyFactory myFactory;
  private final Foo foo;
  private final Bar bar;
  public ParentClass() {
    if(myFactory == null) System.err.println("Error: I should have injected by now!");
    foo = myFactory.create(new Map<String, Object>());
    // etc.
  }
}

Заводской интерфейс

public interface MyFactory {
  Foo create(Map<String, Object> mapA);
  Bar create(Map<String, Object> mapB, Map<String, Object> mapC);
}

Модуль

public class ParentModule extends AbstractModule {
  @Override
  protected void configure() {
    install(new FactoryModuleBuilder()
        .implement(Foo.class, FooImpl.class)
        .implement(Bar.class, BarImpl.class)
        .build(MyFactory.class));
  }

Фуимпл

public class FooImpl implements Foo {
  private final Map<String, Object> mapA;
  @AssistedInject
  public FooImpl(@Assisted Map<String, Object> mapA) {
    this.mapA = mapA;
  }
}

BarImpl очень похож на FooImpl. Что здесь происходит не так? Также обратите внимание, что я пробовал здесь как @AssistedInject, так и @Inject, оба вызывают ошибку.

Выход:

Error: I should have injected by now!
Exception in thread "main" com.google.inject.ProvisionException: Guice provision errors:

1) Error injecting constructor, java.lang.NullPointerException
  at ParentClass.<init>(ParentClass.java:7)
  while locating com.my.package.ParentClass

1 error
        at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987)
        at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
        at com.my.package.ParentMain.main(ParentMain.java:16)
Caused by: java.lang.NullPointerException
        at com.my.package.ParentClass.<init>(ParentClass.java:9)
        at com.my.package.ParentClass$$FastClassByGuice$$d4b3063a.newInstance(<generated>)
        at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40)
        ... 8 more

Обратите внимание, что строка 9 — это строка первого вызова myFactory.create().


person durron597    schedule 07.02.2013    source источник


Ответы (2)


Согласно javadoc Guice, внедрение полей выполняется после внедрения конструктора.

Я предполагаю, что ваш экземпляр ParentClass создан Guice. Когда ваш конструктор ParentClass выполняется, его поле myFactory еще не введено.

person spg    schedule 07.02.2013
comment
Ага, вот почему меня скинули... они используют внедрение полей в своем примере на FactoryModuleBuilder в разделе Использование Factory. - person durron597; 08.02.2013
comment
Проверяю этот ответ, а не другой, потому что это объясняет, ПОЧЕМУ я должен использовать инъекцию конструктора, а не просто говорю мне использовать его. - person durron597; 08.02.2013

Две вещи. Чтобы использовать инъекцию в конструкторе, вы должны использовать инъекцию конструктора:

public class ParentClass {

    private final Foo foo;
    private final Bar bar;

    @Inject
    public ParentClass(MyFactory myFactory) {
        if(myFactory == null) System.err.println("Error: I should have injected by now!");
        this.foo = myFactory.create(new HashMap<String, Object>());
        this.bar = myFactory.create(new HashMap<String, Object>(), new HashMap<String, Object>());
    }
}

Кроме того, поскольку у вашей фабрики есть два параметра одного типа, вам нужно назвать их:

public interface MyFactory {
    Foo create(Map<String, Object> mapA);
    Bar create(@Assisted("B") Map<String, Object> mapB, @Assisted("C") Map<String, Object> mapC);
}

а также

public class BarImpl implements Bar {

    private final Map<String, Object> mapA;
    private final Map<String, Object> mapB;

    @AssistedInject
    public BarImpl(@Assisted("B") Map<String, Object> mapA, @Assisted("C")  Map<String, Object> mapB) {
        this.mapA = mapA;
        this.mapB =mapB;
    }
}
person John Ericksen    schedule 07.02.2013
comment
Хех, так много для SSCCE ... на самом деле это не Object, я просто изменил его, потому что обе карты относятся к другому объекту, который я создал для своего приложения, и подумал, что это не имеет значения. Сейчас попробую ваш вариант, спасибо! - person durron597; 08.02.2013
comment
а, понятно. Надеюсь, что все же помогло. - person John Ericksen; 08.02.2013