2013-08-07 14 views
13

EDIT 2018-02-08: Progetto di esempio che dimostra come eseguire questa operazione in https://github.com/ravn/dagger2-named-string-inject-example - Nota: the whole source is in a single file!Daga: Inietti stringhe @Named?


Sto guardando se dagger può sostituire guice per noi (come la nostra piattaforma Java di implementazione è lenta).

Costruisco una mappa di stringhe di configurazione in fase di esecuzione, che mi piacerebbe avere il pugnale iniettato se necessario.

E.g. Se ho

java.util.Map<String, String> map = new java.util.TreeMap<String, String>(); 
map.put("key", "value"); 

e

@Inject 
Thermosiphon(Heater heater, @Named("key") String value) { 
    this.heater = heater; 
    System.out.println("value =" + value); 
} 

vorrei avere "valore" iniettato in valore.

Gli esempi nel codice sorgente non hanno alcun utilizzo @Named. Provare solo dà la seguente eccezione:

Exception in thread "main" java.lang.IllegalStateException: Errors creating object graph: 
    No binding for @javax.inject.Named(value=key)/java.lang.String required by class bar.Thermosiphon 
    at dagger.internal.ThrowingErrorHandler.handleErrors(ThrowingErrorHandler.java:34) 
    at dagger.internal.Linker.linkRequested(Linker.java:146) 
    at dagger.ObjectGraph$DaggerObjectGraph.getInjectableTypeBinding(ObjectGraph.java:288) 
    at dagger.ObjectGraph$DaggerObjectGraph.get(ObjectGraph.java:249) 
    at app.CoffeeApp.main(CoffeeApp.java:20) 

Come dovrei avvicinarmi a questo?

risposta

13

Suona come si dispone di una mappa e si desidera utilizzare qualcosa che lega questi automaticamente in stringhe di nome. Non puoi farlo automaticamente come in Dagger in Guice, poiché in Guice puoi creare un raccoglitore di proprietà.

Pugnale richiede la conoscenza di tutte le associazioni a tempo di compilazione, al fine di fare l'analisi per garantire che tutte le associazioni e le dipendenze sono soddisfatte

Detto questo, si potrebbe fare qualcosa di simile - è più caldaia piatto, ma è legittimo.

@Module(library = true) 
public class PropertiesModule { 
    public final Properties props; 

    PropertiesModule(Properties props) { 
    this.props = props; 
    } 

    @Provides @Named("property.one") String providePropertyOne() { 
    props.getProperty("property.one", "some default"); 
    } 

    @Provides @Named("property.two") String providePropertyTwo() { 
    props.getProperty("property.two", "some other default"); 
    } 
    ... 
} 

Ciò consentirà per tutti attacchi hte è necessario essere creato, ma per essere soddisfatti dai valori di runtime. Le chiavi, tuttavia, sono conosciute in fase di compilazione (e devono essere, dal momento che stai usando @Named ("stringa letterale") nel tuo codice.) Heck, se hai definito i tuoi nomi di proprietà e valori di default come stringhe costanti puoi persino fare:

@Provides @Named(PROPERTY_NAME_CONSTANT) String a() { 
    props.getProperty(PROPERTY_NAME_CONSTANT, PROPERTY_NAME_CONSTANT_DEFAULT); 
    } 

E 'più piastra della caldaia, ma Pugnale ha, durante il tentativo di eliminare piastra della caldaia molto, preferito l'analisi in fase di compilazione su riduzione assoluta piastra della caldaia detto questo, io propongo una caratteristica che migliorerà. questa situazione, auto-generando un modulo per le proprietà del sistema da un elenco noto, o alcuni di essi. Penso che anche questa piastra di caldaia può essere ridotta

+0

Anche se inizialmente sembrava più un lavoro, penso che possa fornire la documentazione centralizzata di quali proprietà sono spesso necessarie con le applicazioni modulari, specialmente con i nostri casi d'uso. Farò un tentativo. –

+0

Sarebbe davvero bello specificare un elenco di tali proprietà in origine e avere i getter generati dal processore di annotazione. Non ho bisogno di default - ho bisogno di un'eccezione di runtime se non presente con la chiave nel messaggio di errore. –

+0

Sì, penso che abbiamo bisogno di una soluzione di code-gen per questo - qualcosa che genera un modulo da un elenco di proprietà. –

8

È necessario definire un provider nel modulo dagger per l'istanza @Named.

@Provides @Named("foo") String provideFoo() 
{ 
    return "foo string"; 
} 

Quindi è possibile iniettare l'istanza denominata nel costruttore o utilizzando iniezione di campo nella classe dipendente.

public class Thermosiphon 
{ 
    @Inject @Named("foo") String fooString; 

    @Inject public Thermosiphon(Heater heater) 
    { 
     System.out.println("value of fooString is " + fooString); 
    } 
} 
+0

Le mie stringhe sono impostate in file di proprietà letti in fase di runtime e possono contenere valori arbitrari. Ho bisogno di un fornitore per ogni poss chiave? –

+1

Per il momento, non esiste un modo a-runtime per creare nuovi e arbitrari collegamenti, come in Guice, che sconfiggerebbe i severi requisiti di analisi in fase di compilazione di Dagger.È necessario conoscere in anticipo la struttura del proprio oggetto grafico, quindi è necessario disporre di tutti questi collegamenti denominati in anticipo. –