2014-02-11 16 views
6

Bei der Verwendung von Dolch ermöglichen diese Ansätze eine einfache Instanziierung von @Inject-Feldern auf Objekten, die ebenfalls durch Injektion instanziiert werden.Verschachtelte/rekursive Injektionen mit Dolch

Zum Beispiel wird der folgende Code ein Objekt vom Typ Bar in ein bestimmtes Foo-Objekt injizieren. Es wird dies auf eine der beiden angezeigten Arten tun. Das Sly-Feld jedes Balkenobjekts stimmt jedoch nicht mit diesem Verhalten überein.

Foo

public class Foo { 
    @Inject Bar bar; 

    public String getValue() { 
    return "Foo's bar value: " + bar.getValue(); 
    } 
} 

Bang

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!"; 
    } 
} 

Modul

@Module(
    injects = { 
     Foo.class, 
     Bar.class 
    } 
) 
public class ExampleTestModule { 
    @Provides 
    Bar provideBar() { 
    return new Bar(); 
    } 

    @Provides 
    Sly provideSly() { 
    return new Sly(); 
    } 
} 

Tests

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 
} 

In jedem Fall Sly Bar ist nicht/@ injizierte instanziiert wird. Natürlich erlaubt Dagger die Konstruktorinjektion, die das Problem löst. Ich würde gerne wissen, ob es Alternativen gibt, diese Klassen in die Parameterliste von Konstruktoren zu stecken. Was funktioniert gut für dich?

Antwort

9

Also das Problem hier ist, dass Bar @Inject Sly darauf hat, aber dann stellen Sie Bar in einer @Provides-Methode. @Provides-Methoden überschreiben das standardmäßige Instanziierungsverhalten, sodass Sie Dagger anweisen, "new Bar()" zu instanziieren und es als Erfüllung der Bar-Bereitstellung zurückzugeben.

Die einfachste Sache, die Sie tun können, ist einfach löschen Sie die Methode provideBar(), wie es unnötig ist. Wenn ein konkreter Typ einen @Inject-Konstruktor oder ein @Inject-Feld hat, injiziert Dagger seine Abhängigkeiten und erstellt es, es sei denn, es verfügt über einen Konstruktor, auf den nicht zugegriffen werden kann, oder über einen parametrisierten Konstruktor, der kein @Inject hat. Aber Ihr Fall oberhalb der obigen Klasse Bar {} ist für die implizite Bindung ohne Verwendung von @Provides-Methoden völlig geeignet.

Wenn Sie dieses Standardverhalten aus irgendeinem Grund ändern müssen, können Sie es dennoch in einer @Provides-Methode erstellen, aber Sie müssen den injizierten Wert manuell übergeben. @Provides-Methoden können jedoch selbst injiziert werden, indem der @Provides-Methode selbst Parameter hinzugefügt werden. Du könntest das tun.

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

A @Provides Methode nimmt jede Verantwortung für richtig die Instanz Provisioning, einschließlich newing, Aufgaben, jede Initialisierung Logik usw.

Aber, da Ihr Beispiel oben, die einfache Lösung ist, einfach zu löschen provideBar() von Ihrem Modul und lassen Sie Dol Bar automatisch initialisieren.

Es gibt einige verschiedene Alternativen, die Dolch 2 für verschachtelte Injektion zu bevorzugen scheint: Fragen Sie nach einer Komponente, MembersInjector, oder geben Sie Bar einen annotierten @Inject-Konstruktor.

Wenn Bar einen @Inject kommentierten Konstruktor hat, dann können Sie die volle Unveränderlichkeit erreichen:

class Bar { 
    private final Sly sly; 

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

Die andere Alternative, wenn Sie sind zum Teil nur Mitglieder Injektion ist eine @Provides Methode mit einem MembersInjector oder Komponente (MembersTestComponent ?) als Methode Argument:

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

das MembersTestComponent Argument Providing wird leider Paar zu Ihrer Komponente der Module zurück und die Lösung weniger kohäsiv machen. Das Bereitstellen des MembersInjectors ist besonders nützlich, wenn der Balken bereichsspezifische Werte enthält, die von der Komponente bereitgestellt werden (z. B. Benutzer in Tweeter in Jake Whartons Vortrag zu Devoxx 2014).