2015-04-23 14 views
10

W tym pytaniu mówię o Dagger2. Dagger2 składa się głównie ze składników i modułów. Oto przykład:Opóźnione wiązanie z Dagger2 Wykres za pomocą przetwarzania opisów

Załóżmy Mam interfejs:

public interface MyCoolService { 
    void run(); 
} 

i ewentualnego wdrożenia:

public class MyCoolServiceImpl { 
    @Override 
    void run() {} 
} 

mogę połączyć realizację z interfejsem wykorzystaniem Dagger2 prądotwórcze:

@Component(modules = {MyModule.class}) 
@Singleton 
public interface Component {  
    MyCoolService getMyCoolService();  
} 

i

@Module 
public class MyModule { 

    @Provides @Singleton 
    MyCoolService provideMyCoolService() { 
     return new MyCoolServiceImpl(); 
    } 
} 

To było krótkie wprowadzenie do Dagger2. Załóżmy teraz, mam następujący interfejs:

public interface MySecondCoolService { 
    void doCoolStuff(); 
} 

Nie ma realizacja MySecondCoolServiceImpl z MySecondCoolService w kodzie. Zamiast tego mam Annotations @JustForCoolStuff do oznaczania pól i metod. Stworzyłem procesor adnotacji, który zbiera wszystkie te adnotacje i generuje MySecondCoolServiceImpl, który implementuje MySecondCoolService. Kompilator zna nowy interfejs MySecondCoolService przed uruchomieniem procesora adnotacji. Więc mogę zmienić mój komponent jako:

@Component(modules = {MyModule.class}) 
@Singleton 
public interface Component {  
    MyCoolService getMyCoolService(); 
    MySecondCoolService getMySecondCoolService();  
}  

problemem jest to, że nie mam jeszcze implementacji w kodzie i nie wiem nazwę realizacji MySecondCoolService który zostanie wygenerowany przez procesor adnotacji . Dlatego nie mogę połączyć interfejsu z poprawną implementacją w MyModule. Jedyne, co mogę zrobić, to zmienić procesor adnotacji tak, aby generował dla mnie nowy moduł. Mojego procesora adnotacji może wygenerować moduł (MyGeneratedModule), jak poniżej:

@Module 
public class MyGeneratedModule { 

    @Provides @Singleton 
    MySecondCoolService provide MySecondCoolService() { 
     return new MySecondCoolServiceImpl(); 
    } 
} 

Ponownie MyGeneratedModule generowanego przez procesor opisów. Nie mam do niego dostępu przed uruchomieniem procesora adnotacji, ale nie znam nazwy.

Tutaj jest problem: Procesor adnotacji musi jakoś powiedzieć Dagger2, że istnieje nowy moduł, który Dagger2 powinien wziąć pod uwagę. Ponieważ procesory adnotacji nie może zmieniać plików nie może przedłużyć @Component(modules = {MyModule.class}) adnotacji i zmienić go w coś takiego: @Component(modules = {MyModule.class, MyGeneratedModule.class})

Czy istnieje sposób, aby dodać MyGeneratedModule programowo do wykresu zależności dagger2? W jaki sposób mój procesor adnotacji może powiedzieć Daggerowi2, że powinno być nowe połączenie między interfejsem a implementacją, tak jak to opisałem powyżej?


Foray: wiem, że coś takiego można zrobić w Google Guice i Google Gin. Projekt, który to robi GWTP.Nie masz prezentera:

public class StartPagePresenter extends ... { 
    @NameToken("start") 
    public interface MyProxy extends ProxyPlace<StartPagePresenter> { 
    } 
    ... 
} 

który ma @NameToken adnotacji do interfejsu ProxyPlace. W twojej AbstractPresenterModule okablować widok z prezenterem i pełnomocnika:

public class ApplicationModule extends AbstractPresenterModule { 

     bindPresenter(StartPagePresenter.class, 
       StartPagePresenter.MyView.class, StartPageView.class, 
       StartPagePresenter.MyProxy.class); 
     ... 
} 

Jak więc widać żadnej implementacji interfejsu MyProxy wypowiedzenia. Implementacja stworzona przez Generator (podobna do procesora adnotacji, ale dla GWT). Nie Generator generuje realizacja StartPagePresenter.MyProxy i dodać je do systemu guide/gin:

public class StartPagePresenterMyProxyImpl extends com.gwtplatform.mvp.client.proxy.ProxyPlaceImpl<StartPagePresenter> implements buddyis.mobile.client.app.start.StartPagePresenter.MyProxy, com.gwtplatform.mvp.client.DelayedBind { 

    private com.gwtplatform.mvp.client.ClientGinjector ginjector; 
    @Override 
    public void delayedBind(Ginjector baseGinjector) { 
     ginjector = (com.gwtplatform.mvp.client.ClientGinjector)baseGinjector; 
     bind(ginjector.getPlaceManager(), 
      ginjector.getEventBus()); 
     presenter = new CodeSplitProvider<StartPagePresenter>(ginjector.getbuddyismobileclientappstartStartPagePresenter()); 
    ... 
    } 
    } 

+0

Dlaczego nie można po prostu napisać '@Component (moduły = {MyModule.class, MyGeneratedModule.class})' w swojej kod? –

+0

@TavianBarnes Jak napisałem w tekście, nie znam nazwy '' MyGeneratedModule'', która zostanie utworzona. –

+3

Jeśli masz procesor adnotacji generujący klasę, której nazwiska nie znasz z góry, i nie ma innej możliwości jej utworzenia, oznacza to, że masz problem. Najpierw załatw to, reszta przyjdzie. Nieważne, czy użyjesz Sztyletu, czy nie. –

Odpowiedz

0

Cóż, wydaje się, że trzeba będzie uciekać się do refleksji na ten jeden ...

@Module 
public class MyGeneratedModule { 

    @Provides @Singleton 
    MySecondCoolService provide MySecondCoolService() { 
     try { 
      return (MySecondCoolService) Class.forName("package.MySecondCoolServiceImpl").newInstance(); 
     } catch (Exception ex) { ... } 
    } 
} 
1

Czy istnieje sposób na automatyczne dodanie programu MyGeneratedModule do wykresu zależności dagger2?

Tak. Użyj argumentu konstruktora w swoim module.

@Module 
public class MyModule { 
    private final MyCoolService serviceImpl; 

    public MyModule(MyCoolService serviceImpl) { 
    this.serviceImpl = serviceImpl; 
    } 

    @Provides @Singleton 
    MyCoolService provideMyCoolService() { 
    return new MyCoolServiceImpl(); 
    } 
} 

Inicjowanie serviceImpl odbywa się podczas tworzenia wykresu:

DaggerComponent.builder().myModule(new MyModule(serviceImpl)).build(); 
Powiązane problemy