quarkus: Spring JpaRepository doesn't seems to work with ORM named persistence units
Describe the bug
I have set up two persistence units in application.properties (frontend and core)
I have mapped packages using the property quarkus.hibernate-orm."<name>".packages accordingly.
Then I want to use my entities through JpaRepository (quarkus-spring-data-jpa)
Then I get the following generic exception “The default datasource has not been properly configured.”
Expected behavior
It should work I presume
Using the EntityManager, it works fine!
Actual behavior
It throws exception, as follow
java.lang.IllegalStateException: The default datasource has not been properly configured. See https://quarkus.io/guides/datasource#jdbc-datasource for information on how to do that.
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.getEntityManager(AbstractJpaOperations.java:62)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.getEntityManager(AbstractJpaOperations.java:51)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.persist(AbstractJpaOperations.java:93)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl.save(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass.save$$superforward1(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass$$function$$43.apply(Unknown Source)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:50)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:132)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:103)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:57)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32)
at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass.save(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl.save(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass.save$$superforward1(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass$$function$$52.apply(Unknown Source)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_Subclass.save(Unknown Source)
at it.ufficiodiscount.core.model.BrandRepository_fc01783303bb2bc9362ace4366341415b1c24525Impl_ClientProxy.save(Unknown Source)
at org.acme.GreetingResource.makeBrand(GreetingResource.java:41)
at org.acme.GreetingResource_Subclass.makeBrand$$superforward1(Unknown Source)
at org.acme.GreetingResource_Subclass$$function$$5.apply(Unknown Source)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at org.acme.GreetingResource_Subclass.makeBrand(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:91)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Resulted in: org.jboss.resteasy.spi.UnhandledException: java.lang.IllegalStateException: The default datasource has not been properly configured. See https://quarkus.io/guides/datasource#jdbc-datasource for information on how to do that.
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:105)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:359)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
... 15 more
Further analysis
After some debug, I came up to this:
class AbstractJpaOperations:50
String persistentUnitName = entityToPersistenceUnit.get(clazzName);
--> persistentUnitName is null
--> entityToPersistenceUnit is empty
EntityManager
Using the EntityManager, everythings works fine!
How to Reproduce?
I have prepared a small project to reproduce the error.
.\mvnw clean quarkus:dev
Call http://localhost:8080/hello/make-brand-hibernate to create a brand (core persistence unit) using EntityManager - it works
Call http://localhost:8080/hello/make-brand-repository to create a brand (core persistence unit) using JpaRepository - it crashes
Same for Read methods
http://localhost:8080/hello/show-brands-hibernate - it works
http://localhost:8080/hello/show-brands-repository - it crashes
Output of uname -a or ver
No response
Output of java -version
java version “17.0.1” 2021-10-19 LTS
GraalVM version (if different from Java)
No response
Quarkus version or git rev
2.7.3.Final
Build tool (ie. output of mvnw --version or gradlew --version)
No response
Additional information
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 19 (13 by maintainers)
Commits related to this issue
- Support Spring Data repositories with multiple Persistence Units This support requires no extra configuration from users and is possible using the support that Hibernate ORM Panache already has for m... — committed to geoand/quarkus by geoand a year ago
- Support Spring Data repositories with multiple Persistence Units This support requires no extra configuration from users and is possible using the support that Hibernate ORM Panache already has for m... — committed to geoand/quarkus by geoand a year ago
- Merge pull request #31175 from geoand/#24075 Support Spring Data repositories with multiple Persistence Units — committed to quarkusio/quarkus by geoand a year ago
Yes @geoand , I will gladly do that.
Sorry I didn’t mean to say that they shouldn’t be used. More that it’s very likely in a larger project to need additional custom repositories anyway, which diminishes their relevance.
They still can be used of course, I just find them less so central to the design.
In terms of design pattern - what many fail to grasp is that the EntityManager is the repository. It’s a bit of a generic one, so there still is a need for the developer to organize custom queries an recurrent operations for certain areas of the business code in some “place” - now this place can be literally an extension of a Spring JPA Repository or a PanacheRepository but it’s not necessarily one. It also depends on design preference to organize stuff around a specific entity class rather than more fluid business needs.
(and incidentally JPA / Hibernate allows to declare named queries and such on the entity itself)
I generally prefer the “business needs” focus in organizing a large project as that decouples the 1:1 need to map a certain operation on a specific model class - although it’s totally fine if this is a composition and/or decoration of such core helpers the frameworks provide.
And in this sense I think what you suggest @lamemind-ud makes perfect sense. Introduce your own business layer, and feel free to use the various components the platform provides in there: so feel free to mix the use of PanacheRepository, EntityManager and/or JpaRepository. But perhaps limit the flavours to keep it simple 😃
Consider also that
JpaRepositoryis a nice thing we provide for people who are familiar with Spring’s repository so they can keep coding with a familiar API - but if you’re new to these technologies you might as well prefer to skip this one: one less thing to learn, and not particularly relevant to you.