playframework / playframework/play-ebean
Cannot create and properly instantiate an eagerly() bound DI component when dependent on Ebean and Evolutions running.
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 111
- Forks
- 67
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 19
Description
Here is what is happening and maybe I can get some guidance on this. I have read through and tried what was suggested in https://github.com/playframework/play-ebean/issues/51 without any solution.
I created a github project to demonstrate the issue. It is here: https://github.com/justinnichols/broken-play-ebean-di
EDIT>> I have migrated away from using Github. I now have the project here: https://gitlab.com/justinnichols/broken-play-ebean-di
The crux of the problem is that when using Ebean dynamic evolutions, the DI module, when eagerly() started, may or may not be attempted to be instantiated after the evolutions take place. It causes the following issue when starting (randomly, sometimes it works, sometimes it doesn't):
$ activator run
[info] Loading project definition from /home/justin/src/github/justinnichols/broken-play-ebean-di/project
[info] Set current project to broken-play-ebean-di (in build file:/home/justin/src/github/justinnichols/broken-play-ebean-di/)
--- (Running the application, auto-reloading is enabled) ---
[info] p.c.s.NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
(Server started, use Ctrl+D to stop and go back to the console...)
[info] - application - Creating Pool for datasource 'default'
[info] - play.api.db.DefaultDBApi - Database [default] connected at jdbc:mysql://localhost/testdb?useUnicode=yes&characterEncoding=UTF-8&connectionCollation=utf8_general_ci
[error] - application -
! @6o6pp4o27 - Internal server error, for (GET) [/] ->
play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:
1) Error injecting constructor, javax.persistence.PersistenceException: ERROR executing DML bindLog[] error[Table 'testdb.log' doesn't exist]
at components.BrokenPlayEbeanDIComponentImpl.<init>(BrokenPlayEbeanDIComponentImpl.java:15)
at components.BrokenPlayEbeanDIComponentImpl.class(BrokenPlayEbeanDIComponentImpl.java:15)
while locating components.BrokenPlayEbeanDIComponentImpl
at modules.BrokenPlayEbeanDIModule.bindings(BrokenPlayEbeanDIModule.java:17):
Binding(interface components.BrokenPlayEbeanDIComponent to ConstructionTarget(class components.BrokenPlayEbeanDIComponentImpl) eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
while locating components.BrokenPlayEbeanDIComponent
1 error]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:165) ~[play-server_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:121) ~[play-server_2.11-2.4.3.jar:2.4.3]
at scala.Option.map(Option.scala:146) ~[scala-library-2.11.7.jar:na]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:121) ~[play-server_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:119) ~[play-server_2.11-2.4.3.jar:2.4.3]
at scala.util.Success.flatMap(Try.scala:231) ~[scala-library-2.11.7.jar:na]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:119) ~[play-server_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:111) ~[play-server_2.11-2.4.3.jar:2.4.3]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402) ~[na:1.8.0_66]
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) ~[na:1.8.0_66]
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) ~[na:1.8.0_66]
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) ~[na:1.8.0_66]
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) ~[na:1.8.0_66]
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error injecting constructor, javax.persistence.PersistenceException: ERROR executing DML bindLog[] error[Table 'testdb.log' doesn't exist]
at components.BrokenPlayEbeanDIComponentImpl.<init>(BrokenPlayEbeanDIComponentImpl.java:15)
at components.BrokenPlayEbeanDIComponentImpl.class(BrokenPlayEbeanDIComponentImpl.java:15)
while locating components.BrokenPlayEbeanDIComponentImpl
at modules.BrokenPlayEbeanDIModule.bindings(BrokenPlayEbeanDIModule.java:17):
Binding(interface components.BrokenPlayEbeanDIComponent to ConstructionTarget(class components.BrokenPlayEbeanDIComponentImpl) eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
while locating components.BrokenPlayEbeanDIComponent
1 error
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:466) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:184) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110) ~[guice.jar:na]
at com.google.inject.Guice.createInjector(Guice.java:96) ~[guice.jar:na]
at com.google.inject.Guice.createInjector(Guice.java:73) ~[guice.jar:na]
at com.google.inject.Guice.createInjector(Guice.java:62) ~[guice.jar:na]
at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126) ~[play_2.11-2.4.3.jar:2.4.3]
at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93) ~[play_2.11-2.4.3.jar:2.4.3]
at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21) ~[play_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:153) ~[play-server_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:150) ~[play-server_2.11-2.4.3.jar:2.4.3]
at play.utils.Threads$.withContextClassLoader(Threads.scala:21) ~[play_2.11-2.4.3.jar:2.4.3]
at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:150) ~[play-server_2.11-2.4.3.jar:2.4.3]
... 14 common frames omitted
Caused by: javax.persistence.PersistenceException: ERROR executing DML bindLog[] error[Table 'testdb.log' doesn't exist]
at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:90) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:57) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.DefaultPersistExecute.executeInsertBean(DefaultPersistExecute.java:59) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:446) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:480) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:261) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:211) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.DefaultPersister.save(DefaultPersister.java:199) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1461) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1454) ~[avaje-ebeanorm-4.6.2.jar:na]
at dao.LogDaoImpl.create(LogDaoImpl.java:26) ~[na:na]
at components.BrokenPlayEbeanDIComponentImpl.<init>(BrokenPlayEbeanDIComponentImpl.java:16) ~[na:na]
at components.BrokenPlayEbeanDIComponentImpl$$FastClassByGuice$$1a98aa44.newInstance(<generated>) ~[na:na]
at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40) ~[guice.jar:na]
at com.google.inject.internal.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:61) ~[guice.jar:na]
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:105) ~[guice.jar:na]
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:85) ~[guice.jar:na]
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267) ~[guice.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) ~[guice.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103) ~[guice.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40) ~[guice.jar:na]
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:145) ~[guice.jar:na]
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41) ~[guice.jar:na]
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56) ~[guice.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) ~[guice.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103) ~[guice.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40) ~[guice.jar:na]
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:145) ~[guice.jar:na]
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:205) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:199) ~[guice.jar:na]
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:199) ~[guice.jar:na]
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180) ~[guice.jar:na]
... 25 common frames omitted
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'testdb.log' doesn't exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_66]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_66]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_66]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_66]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:400) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.Util.getInstance(Util.java:383) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3847) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3783) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2447) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1901) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2113) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2049) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2034) ~[mysql-connector-java-5.1.36.jar:5.1.36]
at com.zaxxer.hikari.proxy.PreparedStatementProxy.executeUpdate(PreparedStatementProxy.java:61) ~[HikariCP.jar:na]
at com.zaxxer.hikari.proxy.PreparedStatementJavassistProxy.executeUpdate(PreparedStatementJavassistProxy.java) ~[HikariCP.jar:na]
at com.avaje.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:56) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:128) ~[avaje-ebeanorm-4.6.2.jar:na]
at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:80) ~[avaje-ebeanorm-4.6.2.jar:na]
... 58 common frames omitted
Notice the Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'testdb.log' doesn't exist
If I immediately re-run the application, it works perfectly (because that table now exists).
Please if at all possible, can I get some guidance on how to make it work so that I can use Ebean in an eagerly() instantiated component with evolutions turned on?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked broken-play-ebean-di reproducer and inspect components/BrokenPlayEbeanDIComponentImpl.java, modules/BrokenPlayEbeanDIModule.java, and dao/LogDaoImpl.java from the stack trace. Run the application with Ebean dynamic evolutions and an eagerly bound component, then trace whether the component is created before the log table exists. Done requires a reproducible initialization-order diagnosis and a confirmed resolution or documented limitation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, mysql
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100