2014-06-04 17 views
5

Diciamo che ho questa interfaccia:Come posso passare i parametri a un provider con Guice?

public interface DbMapper{ 
} 

E poi questa implementazione:

public interface NameDbMapper extends DbMapper { 

    @SqlUpdate("insert into names (name) values (:name)") 
    void insert(@Bind("name") String name); 
} 

Questa implementazione esiste in un modulo, in modo da non so tutti i DbMappers in fase di compilazione. Scopro DbMappers attraverso la riflessione:

public class GuiceModule extends AbstractModule{ 

    @Override 
    protected void configure() { 
     Reflections reflections = new Reflections("com.company"); 
     Set<Class<? extends DbMapper>> dbMappers = reflections.getSubTypesOf(DbMapper.class); 

     for (Class<? extends DbMapper> dbMapper : dbMappers) { 
      Class<DbMapper> db = (Class<DbMapper>) dbMapper; 
      binder().bind(db).toProvider(DbMapperProvider.class); 
     } 
    } 

Poi ho instansiate mapper nel mio fornitore:

public class DbMapperProvider implements Provider<DbMapper> { 

    private final User user; 

    @Inject 
    public DbMapperProvider(User user) { 
     this.user = user; 
    } 

    @Override 
    public DbMapper get() { 
     String jdbc = user.getJdbc(); 

     DBI userSpecificDatabase = new DBI(jdbc, "user", "password"); 
     //How to replace NameDbMapper.class here with the db variable in GuiceModule? 
     DbMapper dbMapper = userSpecificDatabase.onDemand(NameDbMapper.class); 
     return dbMapper; 
    } 
} 

utente è un'istanza @RequestScoped, quindi non posso creare provider regolarmente GuiceModule. Injecting User funziona, ma come faccio a passare quale DBI di classe dovrebbe usare al posto di hard disk NameDbMapper in DbMapperProvider qui?

Ho provato l'approccio suggerito in http://google-guice.googlecode.com/git/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html ma non è riuscito a farlo funzionare.

L'obiettivo qui è che i moduli non devono scrivere i propri provider, è possibile?

risposta

7

è possibile associare a un'istanza fornitore, come

for (Class<? extends DbMapper> dbMapper : dbMappers) { 
    bind(dbMapper).toProvider(new DbMapperProvider<>(db)); 
} 

Quindi modificare il vostro fornitore in questo modo:.

public class DbMapperProvider<T extends DbMapper> implements Provider<T> { 
    // Use field or method injection 
    @Inject 
    private Provider<User> user; 

    private final Class<T> type; 

    public DbMapperProvider(Class<T> type) { 
     this.type = type; 
    } 

    @Override 
    public T get() { 
     String jdbc = user.get().getJdbc(); 

     DBI userSpecificDatabase = new DBI(jdbc, "user", "password"); 
     DbMapper dbMapper = userSpecificDatabase.onDemand(type); 
     return dbMapper; 
    } 
} 
+0

ottengo "Impossibile accedere all'oggetto con ambito O noi non siamo attualmente all'interno di una Servlet HTTP richiesta, o potresti aver dimenticato di applicare com.google.inject.servlet.GuiceFilter come filtro servlet per questa richiesta. ", Per qualche ragione Guice prova a creare con entusiasmo istanze durante l'inizializzazione? – jontejj

+1

Sicuro. È possibile iniettare un fornitore . –

+0

Wow! Grazie mille per questo. +1 – jontejj