2016-10-19 2 views
1

У меня возникла ошибка при внедрении вспомогательной инъекции.Принудительная инъекция, привязка, привязка

Помощник впрыска работал до тех пор, пока я не представил еще один класс под названием «Менеджер», который полагается на вспомогательный класс Person. Менеджер хочет использовать Person (@Assited Address). Код разрывается в точке построения графика инжектора. Это не идет дальше.

Injector injector = Guice.createInjector(myModule); 

Наглядно, я понимаю, когда объект А помогает тогда B (который зависит от А), на самом деле неявно помощь через А.

Pls примечание, я проверил SO. Я думаю, что кто-то вроде ColinD бы определенно знать ответ How to use Guice's AssistedInject? How to bind Assisted Injected class to interface?

Из любопытства, есть ли хорошие методы/инструменты спот Guice настройки и облегчить кривой обучения? Я включил ProvisionListener и использовал графическую библиотеку. Это немного помогает.

public class Person implements PersonInterface { 
private String name; 
private Address address; 

@Inject 
public Person(String name, @Assisted Address address) { 
     this.name = name; 
     this.address = address; 
} 

} 

public interface PersonInterface { 
    public String getName(); 
    public Address getAddress(); 
} 

public interface PersonFactory { 
    public PersonInterface create(Address address); 
} 

public class Address { 
private final String address; 

public Address(String address) { 
    super(); 
    this.address = address; 
} 
} 

public class Manager implements IManager { 
private final Person person; 
@Inject 
public Manager(Person person) { 
    this.person=person; 
} 
... 
} 

configure() { 

    install(new FactoryModuleBuilder() 
      .implement(PersonInterface.class, Person.class) 
      .build(PersonFactory.class)); 

    // 
    bind(IManager.class).to(Manager.class); 
} 

Фактическая ошибка

com.google.inject.CreationException: Unable to create injector, see the following errors: 

1) No implementation for ...assisted_inject.Address annotated with @com.google.inject.assistedinject.Assisted(value=) was bound. 
    while locating ....assisted_inject.Address annotated with @com.google.inject.assistedinject.Assisted(value=) 
    for parameter 2 at ....assisted_inject.Person.<init>(Person.java:13) 

ответ

2

Когда вы это связывание в ваш модуль:

bind(IManager.class).to(Manager.class); 

Guice будет пытаться создать новый экземпляр класса Manager. Он ищет либо один (но только один) конструктор, аннотированный с помощью @Inject, либо как конструктор отрицательного аргумента нулевого аргумента, который не является приватным. Это конструктор, который Guice будет использовать:

@Inject 
public Manager(Person person) { 
    this.person=person; 
} 

Теперь по тому же правилу Guice будет пытаться создать экземпляр Person с помощью соответствующего конструктора и застрянет здесь:

@Inject 
public Person(String name, @Assisted Address address) { 
    this.name = name; 
    this.address = address; 
} 

Это даст при попытке создать экземпляр адреса из-за аннотации @Assisted. Эта аннотация - это BindingAnnotation, и Guice рассматривает их специально - она ​​пытается найти явные привязки для них, и их нет. Читайте о привязке аннотаций, и вы поймете, почему.

Поскольку ваш менеджер отслеживанием состояния и, видимо, управляет один человек, которого вы можете создать фабрику для этих менеджеров, например:

public interface IManagerFactory { 
    public IManager getIManager(PersonInterface p); 
} 

Тогда вы будете иметь IManager, например:

public interface IManager { 
    public String getPersonName(); 
} 

И применение, которое использует вспомогательную инъекцию:

public class Manager implements IManager { 
    private final PersonInterface person; 

    @Inject 
    public Manager(@Assisted PersonInterface person) { 
     this.person = person; 
    } 

    @Override 
    public String getPersonName() { 
     return person.getName(); 
    } 

} 

Вы можете связать их в вашем модуле:

class MyModule extends AbstractModule { 
    protected void configure() { 
     install(new FactoryModuleBuilder() 
      .implement(PersonInterface.class, Person.class) 
       .build(PersonFactory.class)); 


     install(new FactoryModuleBuilder() 
      .implement(IManager.class, Manager.class) 
      .build(IManagerFactory.class)); 
     } 
    } 

Вводят заводы:

@Inject 
PersonFactory pf; 

@Inject 
IManagerFactory manF; 

и использовать их соответствующим образом, например,:

public void testGuice() { 
    PersonInterface pi = pf.create(new Address("boh")); 
    IManager im = manF.getIManager(pi); 

    System.out.println(im.getPersonName()); 
} 
+0

Lucho, спасибо. Ваше объяснение имело общий смысл. Комментарий стороны, я думал, что BindingAnnotation предназначен для чего-то другого, в частности для привязки заданного типа к нескольким, различным реализациям. My takeaway - это то, что Guice, похоже, по-разному создает путь Assisted и может дать более интеллектуальное сообщение об ошибке, указывающее недостаток в настройке (отсутствует заводская установка) – Vortex

+1

@Vortex Причина, по которой '@ Assisted' является' @ BindingAnotation', в основном из-за того, как это реализовано: эффективно, создаваемые им методы фабрики создают дочерний инжектор, добавляя привязку для '@Assisted Address' к значению параметра и вставляя' Person'. –

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