Reputation: 6606
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."));
}
}
Upvotes: 1
Views: 2735
Reputation: 2826
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
Upvotes: 9
Reputation: 3569
based on the small snippet you've provided i'm running on the assumption that you're using the Play Java API. assuming as much, i'd first recommend you refer to the Play documentation on dependency injection.
if you've bootstrapped your project using one of the Activator templates, you probably ended up with the following two files (among many others):
.
├── app
│ ├── Module.java
└── conf
└── application.conf
"Modules" are one way to configure bindings in Guice (basically what Guice will serve back when a component requests injection of a given type).
in the interest of getting you up and running in the meantime...
...first, in the application.conf
file under the play.modules section, uncomment the line to add to the enabled set of modules, so you'll end up with something like this:
play.modules {
enabled += Module
}
...next, assuming you have an interface named JPAApi
with a concrete implementation JPAApiImpl
... update the Module.java
as follows:
import com.google.inject.AbstractModule;
public class Module extends AbstractModule {
@Override
public void configure() {
bind(JPAApi.class).to(JPAApiImpl.class);
}
}
(or if JPAApi
is a concrete implementation itself, you could just bind that to itself)
restart your application and your controller should be injected.
Upvotes: 0