3

I've created a small project which combines Spring Data, a JPA Repository, EJB/CDI and either Wildfly Swarm or plain Wildfly.

The REST resource (an EJB) calls a CDI bean which has a Spring Data JPA Repository injected.

The initial request to the repository ends in an exception, but subsequent calls work just fine.

2016-12-15 23:03:09,690 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-1) SQL Error: 0, SQLState: null
2016-12-15 23:03:09,690 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-1) javax.resource.ResourceException: IJ000460: Error checking for a transaction
2016-12-15 23:03:10,268 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /Penny: org.jboss.resteasy.spi.UnhandledException: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
...
Caused by: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
...
Caused by: java.lang.Throwable: setRollbackOnly called from:
    at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.setRollbackOnly(TransactionImple.java:339)
    at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.setRollbackOnly(BaseTransaction.java:159)
    at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.setRollbackOnly(BaseTransactionManagerDelegate.java:143)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.markForRollbackOnly(AbstractEntityManagerImpl.java:1509)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1611)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.buildQueryFromName(AbstractEntityManagerImpl.java:753)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createNamedQuery(AbstractEntityManagerImpl.java:730)
    at org.springframework.data.jpa.repository.query.NamedQuery.hasNamedQuery(NamedQuery.java:99)
    at org.springframework.data.jpa.repository.query.NamedQuery.lookupFrom(NamedQuery.java:121)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:212)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:435)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:220)
    at org.springframework.data.jpa.repository.cdi.JpaRepositoryBean.create(JpaRepositoryBean.java:73)
    at org.springframework.data.repository.cdi.CdiRepositoryBean.create(CdiRepositoryBean.java:372)
    at org.springframework.data.repository.cdi.CdiRepositoryBean.create(CdiRepositoryBean.java:170)
    at org.jboss.weld.context.AbstractContext.get(AbstractContext.java:96)
    at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:101)
    at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:99)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:99)
    at ch.maxant.demo.swarmproblems.EmployeeService.findByName(EmployeeService.java)
    at ch.maxant.demo.swarmproblems.EmployeeService$Proxy$_$$_WeldClientProxy.findByName(Unknown Source)
    at ch.maxant.demo.swarmproblems.EmployeeResource.get(EmployeeResource.java)

Debugging, I found out that org.springframework.data.jpa.respository.query.NamedQuery#lookupFrom ends up calling through to org.hibernate.jpa.spi.AbstractentityManagerImpl#buildQueryfromName which seems to throw an IllegalArgumentException: No query defined for that name [Employee.findByName]. That kind of makes sense, in that Spring appears to be loading the named query lazily.

Is this a bug in Spring or is the application not setup properly?

A different project which uses JBoss Wildfly (8) has the same problem: https://github.com/maxant/jee7webappwithspringdata.

Ant Kutschera
  • 6,257
  • 4
  • 29
  • 40
  • See https://stackoverflow.com/questions/41621679/spring-repositories-does-not-work-properly-with-cdi/41636083#41636083. Sorry, I found your post after answering the one I linked to. – mp911de Jan 13 '17 at 13:49
  • Thanks for replying. Unfortunately it doesn't work with Wildfly *Swarm* (I'll test it with just Wildfly later). See https://github.com/maxant/swarm-demo. If I add @Eager, I get this error: "WFLYCTL0412: Required services that are not installed:" => ["jboss.deployment.unit.\"swarm-demo.war\".WeldStartService"], "WFLYCTL0180: Services with missing/unavailable dependencies" => undefined – Ant Kutschera Jan 13 '17 at 22:55
  • as this might be just a swarm problem, I've posted it to here: https://groups.google.com/forum/#!topic/wildfly-swarm/2jUHkF84uqc – Ant Kutschera Jan 13 '17 at 23:01
  • The problem was that the Entity Manager producer which I have to have so that Spring can get a "default" Entity manager was RequestScope. It works once I changed that to Dependent. But shouldn't entity managers be request scoped because they aren't thread safe? – Ant Kutschera Jan 14 '17 at 09:40
  • @mp911de I updated my project which uses a stateless Session EJB to call a CDI dependent scoped bean. There, I log the instance hashcodes of the CDI bean, the injected Spring Data Repository, and an injected Entity Manager (using the PersistenceContext annotation). I then apply a LOT of load. Because of the stateless session EJB, the logs include multiple CDI bean instances, multiple entity manager instances, but ALWAYS the exact same Spring Data Repository. Does the Repository contain some "magic" code to ensure calls to the entity manager which it uses are called in a thread safe manner? – Ant Kutschera Jan 15 '17 at 20:36
  • Spring Data performs no synchronization on the EntityManager. In the case of WildFly, it uses [TransactionScopedEntityManager](https://github.com/wildfly/wildfly/blob/master/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java) that routes calls to the `EntityManager` associated with the transaction. Transactions are bound to threads and so you get the required isolation. – mp911de Jan 15 '17 at 21:01
  • cool, I understand it now. If you add an answer, I'll gladly accept and upvote it. – Ant Kutschera Jan 15 '17 at 21:14

0 Answers0