Let's say I have this interface:
public interface DbMapper{
}
And then this implementation:
public interface NameDbMapper extends DbMapper {
@SqlUpdate("insert into names (name) values (:name)")
void insert(@Bind("name") String name);
}
This implementation exists in a module, so I don't know all DbMappers at compile time. I discover DbMappers through reflection:
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);
}
}
Then I instansiate mappers in my provider:
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;
}
}
User is a @RequestScoped instance, so I can't create providers regularly in GuiceModule. Injecting User works but how do I pass which Class DBI should use instead of hardcode NameDbMapper in DbMapperProvider here?
I've tried the approach suggested in http://google-guice.googlecode.com/git/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html but couldn't get it to work.
The goal here is that modules shouldn't have to write their own providers, is this achievable?
You can bind to a provider instance, like
for (Class<? extends DbMapper> dbMapper : dbMappers) {
bind(dbMapper).toProvider(new DbMapperProvider<>(db));
}
Then modify your provider like this:
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With