playframework / playframework/play-ebean

Cannot create and properly instantiate an eagerly() bound DI component when dependent on Ebean and Evolutions running.

Open
#65 18 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

status:backlog
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.