2014-02-11 4 views
6

При использовании кинжала, какие подходы позволят создать свободную/легкую инстанцировку полей @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(); 
    } 
} 

Sly

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 
} 

В любом случае, Sly Bar является не инстанцирован/@ Введенный. Конечно, Кинжал допускает инъекцию конструктора, которая решает проблему. Я хотел бы знать, есть ли альтернативы переустановке этих классов в список параметров конструкторов. Что хорошо работает для вас?

ответ

9

Итак, проблема в том, что на баре есть @Inject Sly, но затем вы предоставляете Bar в методе @Provides. @Provides методы переопределяют поведение экземпляров по умолчанию, поэтому вы говорите Кинжалу о создании «нового бара()» и возвращаете его как выполнение положения Бар.

Самое простое, что вы можете сделать, это просто удалить метод grantBar(), поскольку он не нужен. Если конкретный тип имеет конструктор @Inject или поле @Inject, Dagger будет вводить свои зависимости и создавать его, если только он не имеет недоступного конструктора или конструктора с параметрами, который не имеет @Inject. Но ваш случай выше класса Bar {} выше полностью подходит для неявного связывания без использования методов @Provides.

Если по какой-либо причине вам необходимо изменить поведение по умолчанию, вы все равно можете создать его в методе @Provides, но вы должны вручную передать введенное значение. Однако методы @Provides могут сами вводиться путем добавления параметров к самому методу @Provides. Таким образом, вы могли бы это сделать.

@Provides 
Bar provideBar(Sly sly) { 
    Bar bar = new Bar(); 
    bar.sly = sly; 
    return bar; 
} 

A @Provides метод берет на себя всю ответственность за надлежащую инициализацию экземпляра, в том числе newing, назначения, любую логику инициализации и т.д.

Но, учитывая ваш пример выше, простое решением является просто удалить provideBar() из вашего модуля и дайте Dagger автоматически инициализировать Bar.

Есть несколько альтернатив, которые Dagger 2, по-видимому, предпочитает вложенную инъекцию: попросите компонент, MemberInjector или дайте Bar аннотированный конструктор @Inject.

Если бар имеет @Inject аннотированный конструктор, то вы можете достичь полной неизменности:

class Bar { 
    private final Sly sly; 

    @Inject 
    public Bar(Sly sly) { 
    this.sly = sly; 
    } 
} 

Другой вариант, когда вы только частично инъекционного членов является использование метода @Provides с MembersInjector или компонента (MembersTestComponent ?) в качестве аргумента метода:

@Provides 
Bar provideBar(MembersInjector<Bar> injector) { 
    Bar bar = new Bar(); 
    injector.inject(bar); 
    return bar; 
} 

Обеспечение MembersTestComponent аргумента, к сожалению, пару модуля обратно к компоненту и сделать решение более сплоченной. Предоставление MembersInjector особенно полезно, если Bar содержит облачные значения, предоставленные Компонентом (например, пользователь внутри Tweeter в разговоре Devoxx 2014 от Jake Wharton).

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