I don't want to define the default database configuration in the application.conf
file. Instead, I want to construct the default EbeanServer programmatically and inject it myself into the DAO.
The problem I am having is, if I create a guice binding for a EbeanServer provider and not define any configuration in the application.conf
file, play errors out saying it cannot find a default configuration.
Here's the code I have:
public class EbeanServerProvider implements Provider<EbeanServer> {
final Logger.ALogger log = Logger.of(this.getClass());
@Override
public EbeanServer get() {
ServerConfig serverConfig = new ServerConfig();
DataSourceConfig dataSourceConfig = new DataSourceConfig();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Config dbConfig = ConfigFactory.load(classLoader,"env/default.conf");
/* Read the config files */
final String DB_DRIVER = dbConfig.getString("db.default.driver");
final String DB_URL = dbConfig.getString("db.default.url");
final String DB_USERNAME = dbConfig.getString("db.default.username");
final String DB_PASSWORD = dbConfig.getString("db.default.password");
log.debug("{}",DB_DRIVER);
log.debug("{}",DB_URL);
log.debug("{}",DB_USERNAME);
log.debug("{}",DB_PASSWORD);
/* Load the database driver */
dataSourceConfig.setDriver(DB_DRIVER);
try{
Class.forName(DB_DRIVER).newInstance();
}
catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
log.error("Unable to load database driver:{}",DB_DRIVER);
throw new WrappedServerError(InternalErrorCode.TA_ERROR,"Failed to load database driver",e);
}
/* Set the data source configs */
dataSourceConfig.setUrl(DB_URL);
dataSourceConfig.setUsername(DB_USERNAME);
dataSourceConfig.setPassword(DB_PASSWORD);
dataSourceConfig.setCaptureStackTrace(true);
serverConfig.setDataSourceConfig(dataSourceConfig);
serverConfig.setName("mysql");
serverConfig.setDefaultServer(true);
serverConfig.setDdlGenerate(false);
serverConfig.setDdlRun(false);
serverConfig.setRegister(true);
EbeanServer dbServer=null;
try {
dbServer = EbeanServerFactory.create(serverConfig);
}
catch (Exception e){
throw new WrappedServerError(InternalErrorCode.TA_INIT_ERROR,"Failed to create ebean server",e);
}
return dbServer;
}
}
application.conf
:
# Ebean configuration
ebean.default = ["com.giraffe.models.*"]
guice module binding
//Ebean server
bind(EbeanServer.class).toProvider(EbeanServerProvider.class).asEagerSingleton();
Error:
play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, Configuration error: Configuration error[null]
while locating play.db.ebean.DefaultEbeanConfig$EbeanConfigParser
at play.db.ebean.EbeanModule.bindings(EbeanModule.java:24):
Binding(interface play.db.ebean.EbeanConfig to ProviderConstructionTarget(class play.db.ebean.DefaultEbeanConfig$EbeanConfigParser) eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
while locating play.db.ebean.EbeanConfig
for parameter 0 at play.db.ebean.EbeanDynamicEvolutions.<init>(EbeanDynamicEvolutions.java:36)
at play.db.ebean.EbeanDynamicEvolutions.class(EbeanDynamicEvolutions.java:33)
while locating play.db.ebean.EbeanDynamicEvolutions
at play.db.ebean.EbeanModule.bindings(EbeanModule.java:23):
Binding(class play.api.db.evolutions.DynamicEvolutions to ConstructionTarget(class play.db.ebean.EbeanDynamicEvolutions) eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
while locating play.api.db.evolutions.DynamicEvolutions
Caused by: Configuration error: Configuration error[null]
at play.api.Configuration$.configError(Configuration.scala:178)
at play.api.Configuration.reportError(Configuration.scala:829)
at play.Configuration.reportError(Configuration.java:351)
at play.db.ebean.DefaultEbeanConfig$EbeanConfigParser.parse(DefaultEbeanConfig.java:81)
at play.db.ebean.DefaultEbeanConfig$EbeanConfigParser.get(DefaultEbeanConfig.java:60)
at play.db.ebean.DefaultEbeanConfig$EbeanConfigParser.get(DefaultEbeanConfig.java:44)
at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
at com.google.inject.internal.BoundProviderFactory.provision(BoundProviderFactory.java:72)
at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:61)
at com.google.inject.internal.BoundProviderFactory.get(BoundProviderFactory.java:62)
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
I was able to solve the problem after following the hint from @BatteryAcid:
'ebean.default = ['models.*]'
setting fromapplication.conf
file. I added the following tobuild.sbt
.build.sbt
This ensures that your models are enhanced.
EbeanServerProvider.java
The thing to note here is the
serverConfig.addClass
method. You will have to register all your model classes this way. Which means if you have 10 models, you will have 10 such calls toserverConfig.addClass
. Which is stupid.There is a
serverConfig.addPackage
method, which supposedly can read all the models in a given package and register it with EbeanServer. But it did not work me. Since I currently have only a few models this solution works for now.Guice binding
If any of you reading this has a better solution, please do post it here.
UPDATE
I was able to get around your exception by removing the
ebean.default
from the application.conf and using thisget()
in EbeanServerProvider. The only problem is that I couldn't get ebean to scan a whole package, so I manually listed out my model classes (Configuration) - that would be a pain but at least I've narrowed it down.----- You can probably ignore the below ---
Take a look at this, I haven't tested it myself but maybe it will get you pointed in the right direction.
According to the Play 2.4 docs you can implement ServerConfigStartup to customize an ebean server before it starts: