2011-12-04 10 views
7

Ho una webapp che usa GIN per iniettare dipendenze al punto di ingresso.Guice/Gin. Come iniettare più implementazioni

private InjectorService injector = GWT.create(InjectorService.class); 

@GinModules({PlaceContollerInject.class, RootViewInject.class}) 
public interface InjectorService extends Ginjector { 

    RootView getRootView(); 
    PlaceController getPlaceConroller(); 

} 

public class RootViewInject extends AbstractGinModule { 

    @Override 
    protected void configure() { 
    bind(RootView.class).to(RootViewImpl.class); 
    } 
} 

ho bisogno di una versione mobile che utilizzano implementazione RootView diverso. Le dipendenze sono descritti nella seguente modulo di

public class RootViewMobileInject extends AbstractGinModule { 

    @Override 
    protected void configure() { 
    bind(RootView.class).to(RootViewMobileImpl.class); 
    } 
} 

La domanda è: come scegliere la dipendenza necessario condizionale se abbiamo bisogno versione mobile o di default. Ho visto GWT-GIN Multiple Implementations, ma non ho capito quella soluzione perché il Provider rompe la catena delle dipendenze e il Modello di fabbrica rompe la testabilità. Nel video "Big Modular Java with Guice" here (12 minute) L'iniettore di Guice con moduli è stato presentato in sostituzione delle fabbriche. Quindi la mia domanda è se dovessi creare diverse Ginjector per le versioni mobile e di default (come MobileFactory e DefaultFactory) della mia app o sarebbe una cattiva pratica e dovrei configurare un'istanza di Ginjector con tutte le versioni necessarie. Ad esempio con i collegamenti di annotazione come questo.

public class RootViewMobileInject extends AbstractGinModule { 

    @Override 
    protected void configure() { 
    bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class); 
    } 
} 

e utilizzare legature @Mobile annotati in GWT voce punto

@Inject 
    private void setMobileRootView(@Mobile RootView rw) { 
    this.rw = rw; 
    } 

In un tale esempio semplificato come sopra potrebbe essere possibile. Ma se un'applicazione ha più dipendenze che richiedono versioni mobili e predefinite. Sembra che tornino a "fabbriche" (come si diceva la presentazione di Guice) non "testabili". Ci scusiamo per il mio inglese. Qualsiasi aiuto è apprezzato.

+1

Volevo solo aggiungere che l'idea qui e la soluzione di @aldanok potrebbero essere utilizzate anche per la personalizzazione specifica del client nell'applicazione. Client specifico: gwt.xml + modulo gin + implementazioni di interfaccia. – MeTTeO

risposta

9

Credo che vorrai utilizzare l'associazione differita GWT, utilizzando la sostituzione di classe per associare una versione diversa di InjectorService a seconda dello user-agent. Questo garantirà che la versione mobile abbia solo le implementazioni mobili compilate (e scaricate)

Quindi si dovrebbe avere InjectorServiceDesktop, InjectorServiceMobile, che si estendono entrambi da InjectorService, quindi GWT.create (InjectorService.class), e che il binding differito decida quale implementazione dovrebbe usare.

http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement

Un esempio di Ginjector con tutte le versioni sembra male in quanto significa tutto il codice per entrambe le versioni è sempre scaricato (e certamente non si vuole scaricare tutte le vostre opinioni sul desktop nel tuo app mobile)

MODIFICA: come sottolinea Thomas nei commenti, dal momento che gli Iniettori sono classi generate, dovrai inserire ciascun InjectorServiceXXX in una semplice classe di supporto che GWT.create() 's injectorServiceXXX, e utilizzare la sostituzione per passare tra i titolari.

+5

+1, tranne che non funzionerà in questo modo: non è possibile avere la sostituzione e la generazione allo stesso tempo, è necessario creare un "InjectorServiceHolder" con 2 sottoclassi. Ognuno 'GWT.create()' una diversa sottointerfaccia 'InjectorService'. Usa la sostituzione sul "titolare" per scegliere quale 'InjectorService' usare, e' GWT.create() 'sulla sottointerfaccia' InjectorService' farà scattare la generazione del codice GIN. –

+0

evviva per la correzione! aggiornato la risposta. – aidanok

+0

Grazie per la risposta. Sono piuttosto d'accordo con te sul fatto che dovrei usare diversi Giniettori. è molto semplice e conveniente. Ma cosa pensi di fare con lo stesso problema sul lato di Guice che non ha la tecnica di rilegatura differita. Quale tecnica preferiresti sovrascrivere il modulo di base - [Modules.override] (http://stackoverflow.com/questions/7314323/how-to-override-binding-in-gin) o solo l'ereditarietà di Java. Perché? E altro ancora ... come configurare Ginjector/Injector quando tutte le versioni sono necessarie (diciamo DefaultView e LoggedInView)? – trupanka

1

Fare quello che vuoi è in realtà piuttosto complicato perché la tua interfaccia di iniettore comune, che è annotata con il tuo modulo Gin, non può puntare a un modulo Gin astratto. Il modulo Gin indicato dalla tua interfaccia di Ginjector deve essere concreto. Un modulo concreto non può soddisfare più configurazioni contemporaneamente.

Quindi, ciò che si fa è: (a) Creare l'interfaccia di Ginjector, ad esempio ClientGinjector e il modulo, ClientModule, per un'applicazione desktop.

(b) Creare una seconda interfaccia Ginjector, ad esempio ClientGinjectorTablet, estendendo quella creata in (a) ma con un'annotazione GinModule che punta a un modulo diverso, ad esempio ClientModuletablet.

- Ora si dispone di due interfacce Ginjecor una predefinita e una secondaria per tablet, ciascuna delle quali punta a un modulo con le proprie implementazioni di Configure().

(c) Ora si desidera creare Factory per ottenere l'implementazione giusta di Ginjector. Puoi farlo perché il Ginjector che hai caricato (a) e (b) ha un demonitador comune che è l'interfaccia predefinita creata in (a). Così si crea una facotry astratta con un metodo come questo: public abstract ClientGinjector getInjector(); È possibile creare due classi concreti per i bambini Uno per ottenere il proiettore/default del desktop e un altro per ottenere il Tablet Ginjector.

(d) Ora si configura il tuo gwt.xml del modulo come l'I/O di Google su youtube spiega che dovresti ottenere la facotry desiderata durante il runtime, usando le associazioni differite GWT per ogni tua fabbrica di Ginjector.

(e) Sul punto di accesso, la prima cosa da fare è non procurarsi un Giniettore, ma la fabbrica per Giniettori che utilizza la rilegatura differita GWT. Si chiama il metodo astratto che restituisce un ClientGinjector, set.

(f) Il fallimento epico alla fine. Guice non ti permetterà di legare due volte la stessa chiave (classe più annotazione), anche se useresti iniettori diversi (uno per desktop e uno per tablet). Sembra che le definizioni di legame chiave siano globali, non appena si hanno due moduli che ridefiniscono le stesse chiavi, questa è la fine dell'avventura.