Guice, bind different database provider based on yaml config
Question
I have an application config file that looks something like this:
database:
type: [db-type]
username: [name]
password: [pw]
server: [ip]
database: [db-name]
db-type can be any of the following: {postgresql, mysql, mssql, file}. I wanted to configure the binding, such that (it's hibernate based) the app loads a special Provider of SessionFactory depending on which of the values is used, i.e. a PostgresqlSessionFactoryProvider.
The problem is, that Guice also takes care of injecting an instance of Config.class into classes that need access to it. Now I need to access the config, while setting up the binding... It's sort of a chicken-egg problem.
How do I get around that?
Solution
I have found a way to do this. It might not be the best way to do it, so if you know better, I will still look at the answers.
The point is, that the binder does first have to be completely configured, so it can provide an instance of Config.class.
So I came up with a custom Provider for SessionFactory.class that needs a config and the guice injector itself, so that when all the info has been slurped by guice, it has the means to provide a different implementation based on the config.
public class SessionFactoryProvider implements Provider<SessionFactory> {
private Config config;
private Injector injector;
@Inject
public SessionFactoryProvider(Config config, Injector injector) {
this.config = config;
this.injector = injector;
}
@Override
public SessionFactory get() {
switch (config.database.type) {
case postgresql:
return injector.getInstance(PostgresqlSessionFactoryProvider.class).get();
case mysql:
return injector.getInstance(MysqlSessionFactoryProvider.class).get();
case file:
return injector.getInstance(FileBasedSessionFactoryProvider.class).get();
/* some more providers... */
default:
return injector.getInstance(FileBasedSessionFactoryProvider.class).get();
}
}
}
What do you think? Is this a good way to do this?