2015-04-23 10 views
10

In questa domanda parlo di Dagger2. Dagger2 è costituito essenzialmente da componenti e moduli. Ecco un esempio:Legame ritardato al grafico di Dagger2 utilizzando l'elaborazione di annotazione

supponga che ho un'interfaccia:

public interface MyCoolService { 
    void run(); 
} 

e una possibile implementazione:

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

ho potuto collegare l'implementazione con l'interfaccia utilizzando Dagger2 generatrice:

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

e

@Module 
public class MyModule { 

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

Questa è stata una breve introduzione a Dagger2. Supponiamo ora ho la seguente interfaccia:

public interface MySecondCoolService { 
    void doCoolStuff(); 
} 

non ci sono implementazioni MySecondCoolServiceImpl di MySecondCoolService nel codice. Invece, ho un Annotations @JustForCoolStuff per contrassegnare campi e metodi. Ho creato un processore Annotation che raccoglie tutte queste annotazioni e genera MySecondCoolServiceImpl che implementa MySecondCoolService.

I il compilatore conosce la nuova interfaccia MySecondCoolService prima che il processore di annotazione sia in esecuzione. Così ho potuto cambiare il mio Componente come:

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

Il problema è che non ho un'implementazione ancora nel codice e non so il nome della realizzazione di MySecondCoolService che viene generato da un processore di annotazione . Pertanto, non è possibile cablare l'interfaccia con l'implementazione corretta in MyModule. Quello che posso fare è cambiare il mio processore di annotazione in modo tale da generare un nuovo modulo per me. Mio processore annotazione potrebbe generare un modulo (MyGeneratedModule) come questo:

@Module 
public class MyGeneratedModule { 

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

Ancora MyGeneratedModule è generato da un processore annotazione. Non ho accesso ad esso prima di eseguire il processore di annotazione anche io non conosco il nome.

Ecco il problema: Il processore di annotazione deve in qualche modo dire a Dagger2 che c'è un nuovo modulo che Dagger2 dovrebbe prendere in considerazione. Dal momento che i processori di annotazione non possono modificare i file non può estendere la @Component(modules = {MyModule.class}) annotazione e trasformarla in qualcosa di simile: @Component(modules = {MyModule.class, MyGeneratedModule.class})

C'è un modo per aggiungere MyGeneratedModule di programmazione al grafico dagger2 dipendenze? Come può il mio Annotation Processor dire a Dagger2 che dovrebbe esserci un nuovo cablaggio tra un'interfaccia e un'implementazione come ho descritto sopra?


Foray: So che una cosa del genere può essere fatto in Google Guice e Google Gin. Un progetto che lo fa è GWTP.Ci si dispone di un presentatore:

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

che ha un @NameToken un'annotazione a un'interfaccia ProxyPlace. Nella tua AbstractPresenterModule di cablare la vista con il presentatore e il proxy:

public class ApplicationModule extends AbstractPresenterModule { 

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

Come quindi si può non vedere implementazione dell'interfaccia MyProxy è dato. L'implementazione creata da un generatore (simile al processore di annotazione ma per GWT). Ci Generator genera l'attuazione di StartPagePresenter.MyProxy e aggiungerlo al sistema di guida/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

Perché non si può solo scrivere '@Component (moduli = {MyModule.class, MyGeneratedModule.class})' nella tua codice? –

+0

@TavianBarnes Come ho descritto nel testo non conosco il nome di '' MyGeneratedModule'' che verrà creato. –

+3

Se si dispone di un processore di annotazione che genera una classe il cui nome non si conosce in anticipo e nessun altro modo per istanziarla, si ha un problema. Risolvi prima questo, il resto seguirà. Indipendentemente dal fatto che tu usi Dagger o meno, in realtà è irrilevante. –

risposta

0

Beh, sembra che si dovrà ricorrere alla riflessione per questo uno ...

@Module 
public class MyGeneratedModule { 

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

C'è un modo per aggiungere MyGeneratedModule al grafo delle dipendenze di dagger2?

Sì. Utilizza un argomento costruttore nel tuo modulo.

@Module 
public class MyModule { 
    private final MyCoolService serviceImpl; 

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

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

inizializzazione del serviceImpl è fatto quando si genera il grafico:

DaggerComponent.builder().myModule(new MyModule(serviceImpl)).build(); 
Problemi correlati