При использовании кинжала, какие подходы позволят свободно / просто создавать экземпляры @Inject для объектов, которые также создаются путем инжекции.
Например, приведенный ниже код вводит объект типа Bar в заданный объект Foo. Он будет делать это одним из двух способов отображения. Однако Sly-поле каждого объекта Bar не соответствует этому поведению.
Foo
public class Foo { @Inject Bar bar; public String getValue() { return "Foo's bar value: " + bar.getValue(); } }
бах
public class Bar { @Inject Sly sly; public String getValue() { return "Bar's sly value: " + sly.getValue(); } }
лукавый
public class Sly { public String getValue() { return "Hey!"; } }
модуль
@Module( injects = { Foo.class, Bar.class } ) public class ExampleTestModule { @Provides Bar provideBar() { return new Bar(); } @Provides Sly provideSly() { return new Sly(); } }
тесты
public void testWorksWithInject() { Foo foo = new Foo(); ObjectGraph.create(new ExampleTestModule()).inject(foo); assertEquals("...", foo.getValue()); // NullPointerException } public void testWorksWithGet() { Foo foo = ObjectGraph.create(new ExampleTestModule()).get(Foo.class); assertEquals("...", foo.getValue()); // NullPointerException }
В любом случае, Bar's Sly не создается / @ Injected. Конечно, Кинжал допускает инъекцию конструктора, которая решает проблему. Я хотел бы знать, есть ли альтернативы переустановке этих классов в список параметров конструкторов. Что хорошо работает для вас?
Таким образом, проблема здесь в том, что на баре есть @Inject Sly, но затем вы предоставляете Bar в методе @Provides. @Provides методы переопределяют поведение экземпляров по умолчанию, поэтому вы говорите Кинжалу о создании «нового бара ()» и возвращаете его как выполнение положения Бар.
Самое простое, что вы можете сделать, это просто удалить метод enableBar (), поскольку он не нужен. Если конкретный тип имеет конструктор @Inject или поле @Inject, Dagger будет вводить свои зависимости и создавать его, если только он не имеет недоступного конструктора или конструктора с параметрами, который не имеет @Inject. Но ваш случай выше класса Bar {} выше полностью подходит для неявного связывания без использования методов @Provides.
Если по какой-то причине вам нужно изменить поведение по умолчанию, вы все равно можете создать его в методе @Provides, но вы должны вручную передать введенное значение. Однако методы @Provides могут сами вводиться путем добавления параметров к самому методу @Provides. Таким образом, вы могли бы это сделать.
@Provides Bar provideBar(Sly sly) { Bar bar = new Bar(); bar.sly = sly; return bar; }
Метод @Provides берет на себя всю ответственность за надлежащее предоставление экземпляра, включая новизну, назначения, любую логику инициализации и т. Д.
Но, учитывая ваш пример выше, простое решение состоит в том, чтобы просто удалить enableBar () из вашего модуля и позволить Dagger автоматически инициализировать Bar.
Существуют различные альтернативы, которые Dagger 2, по-видимому, предпочитает вложенную инъекцию: попросите компонент, MemberInjector или дайте Bar аннотированный конструктор @Inject.
Если Bar имеет @Inject аннотированный конструктор, то вы можете достичь полной неизменности:
class Bar { private final Sly sly; @Inject public Bar(Sly sly) { this.sly = sly; } }
Другой альтернативой, когда вы только частично вводите членов, является использование метода @Provides с элементом MemberInjector или компонентом (MembersTestComponent?) В качестве аргумента метода:
@Provides Bar provideBar(MembersInjector<Bar> injector) { Bar bar = new Bar(); injector.inject(bar); return bar; }
Предоставление аргумента MembersTestComponent, к сожалению, приведет модуль обратно к вашему компоненту и сделает решение менее связным. Предоставление MembersInjector особенно полезно, если Bar содержит облачные значения, предоставленные Компонентом (например, пользователь внутри Tweeter в разговоре Devoxx 2014 от Jake Wharton).