greyfox greyfox - 1 month ago 22
Java Question

Play Framework Inject Error

I am trying to inject the JPAApi into my controller using Play 2.5 but I keep getting the following exception.

com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Error injecting constructor, java.lang.NoClassDefFoundError: org/dom4j/io/STAXEventReader
at play.db.jpa.DefaultJPAApi$JPAApiProvider.<init>(DefaultJPAApi.java:39)
at play.db.jpa.DefaultJPAApi$JPAApiProvider.class(DefaultJPAApi.java:34)
while locating play.db.jpa.DefaultJPAApi$JPAApiProvider
while locating play.db.jpa.JPAApi
for parameter 0 at controllers.HomeController.<init>(HomeController.java:20)
while locating controllers.HomeController
for parameter 1 at router.Routes.<init>(Routes.scala:40)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:200)
while locating play.api.http.JavaCompatibleHttpRequestHandler
while locating play.api.http.HttpRequestHandler
for parameter 4 at play.api.DefaultApplication.<init>(Application.scala:221)
at play.api.DefaultApplication.class(Application.scala:221)
while locating play.api.DefaultApplication
while locating play.api.Application

1 error
com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025)
com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:405)
play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:400)
play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:123)
play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:158)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:155)
play.utils.Threads$.withContextClassLoader(Threads.scala:21)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:155)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:126)
scala.Option.map(Option.scala:146)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:126)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:124)
scala.util.Success.flatMap(Try.scala:231)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:124)
play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:116)
scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)


This is my controller.

public class HomeController extends Controller {

private JPAApi jpaApi;

@Inject
public HomeController(JPAApi jpaApi) {
this.jpaApi = jpaApi;
}

public Result index() {
jpaApi.withTransaction(entityManager -> {
Query query = entityManager.createNativeQuery("select max(age) from people");
return (Long) query.getSingleResult();
});
return ok(index.render("Your new application is ready."));
}

}

Answer

You just bumped into a bug in sbt (the build tool Play is using). This bug arrises with Hibernate version 5.2.1 (but not with 5.2.0).

Hibernate 5.2.1 started do exclude all transitive dependencies of dom4j with a maven syntax that sbt can't handle yet.

The workaround for now is to add

"dom4j" % "dom4j" % "1.6.1" intransitive()

to your libraryDependencies in build.sbt (in parallel to the Hibernate dependency).

For more detailed information have a look at the sbt bug itself which can be found here: https://github.com/sbt/sbt/issues/1431

The Hibernate bug I reported (but has been closed as it turned out to be a sbt issue) can be found here: https://hibernate.atlassian.net/browse/HHH-10916