Does anyone tried integrating spring-data-jpa with java-ee application?
I'm using glassfish3 as an application container.
I followed an official spring-data-jpa tutorial and created a class:
public class EntityManagerFactoryProducer {
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
return Persistence.createEntityManagerFactory("myPU");
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
#Produces
#RequestScoped
public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
public void close(#Disposes EntityManager entityManager) {
entityManager.close();
}
}
But when I try to deploy my application, I'm getting an exception:
Error occurred during deployment: Exception while preparing the app : Could not resolve a persistence unit corresponding to the persistence-context-ref-name [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean/entityManager] in the scope of the module called [App]. Please verify your application.. Please see server.log for more details.
Command deploy failed.
What am I missing? Should I also have another configuration file or maybe some xml file?
Since you are in a Java EE Application Container you do not want to create your own Persistence instance. The example from the Spring Data documentation you used is for CDI environmets that do not have built in JPA support. Glasfish creates EntityManagerFactory and EntityManager for you. You only need to republish it as CDI bean. So in your case it is important to use the second example shown in the documentation:
public class EntityManagerProducer {
#Produces
#RequestScoped
#PersistenceContext
private EntityManager entityManager;
}
It's a bit more tricky that what is told in official documentation. To handle properly a Spring Repository in a CDI env, you need to declare:
a dependent entity manager producer
#Produces #Dependent #PersistenceContext
EntityManager entityManager;
a eager repository
#Eager public interface TestRepository extends CrudRepository<TestEntity, Long>
Then you'll be able to #Inject the repository in a CDI managed Bean.
If you don't use the #Dependent and the #Eager annotation, Spring will cause exceptions at the initialization of the repositories, leading to uncatch expcetions on the first request made against it.
References:
Spring Data JPA repositories use in EJB timer causes TransactionRequiredException
Getting a reference to EntityManager in Java EE applications using CDI
Related
I am developing a project with spring framework.
I have following architecture: all database code is in dao classes, all application logic is in service classes, http requests are processed using spring mvc rest controllers.
#Repository
public class UserDao {
#PersistenceContext
private EntityManager em;
public void editUser(User user) {
...
}
}
#Service
public class UserService {
#Autowired
private UserDao userDao;
#Transactional
public void editUser(User user) {
...
}
}
#RestController
#RequestMapping(value = "/UserCtrl", produces = "application/json;charset=UTF-8")
public class UserCtrl {
private static final Logger logger = LogManager.getLogger(AppConfig.LOGGER_NAME);
#Autowired
private ApplicationContext appContext;
#RequestMapping(value = "/editUser")
public ActionResult editUser(#ModelAttribute User user) {
ActionResult rslt = new ActionResult();
try {
UserService userService = appContext.getBean(UserService.class);
userService.editUser(user);
rslt.setSuccess(true);
} catch (Exception ex) {
logger.error("editUser", ex);
rslt.setSuccess(false);
}
return rslt;
}
}
This code works correctly.
One thing I cannot understand is how aop proxy of UserService bean starts transaction, when EntityManager is injected only in UserDao class. Can somebody explain me how this works and how EntityManager lifecycle is managed by spring framework ?
Any help appreciated.
The TransactionManager is responsible for managing the transaction boundaries
in Spring Framework.
When you annotate the business method with #Transactional you are instrumenting the method with an aspect.
Before executing the method, this aspect interact with TransactionManager which decides if it is necessary to create a new Transaction or use a preexisting one. In the case of create a new Transaction, a new Entity Manager is created from EntityManagerFactory and is associated to the current thread alonside with the Transaction.
The EntityManager is responsible to iterate with the database. When you inject it with #PersistenceContext, Spring injects an proxy to the EntityManager.
Whenever an operation is executed in the EntityManager proxy it looks the EntityManager associated with the thread.
Based on the snippet of code you provide you are using spring with some implementation of JPA you are using J2EE container for your web application and bases on my guess I think this is good article about how things works.
Basic concepts :
EntityManager - A class that manages the persistent state(or lifecycle) of an entity.
Persistence Unit - is a named configuration of entity classes.
Persistence Context - is a managed set of entity instances. The entities classes are part of the Persistence Unit configurations.
Managed Entities - an entity instance is managed if it is part of a persistence context and that Entity Manager can act upon it.
Based on this article you use Container Managed EntityManager by using #PersistenceContext
When a container of the application(be it a Java EE container or any other custom container like Spring) manages the lifecycle of the Entity Manager, the Entity Manager is said to be Container Managed. The most common way of acquiring a Container Managed EntityManager is to use #PersistenceContext annotation on an EntityManager attribute.
And the injection is like this :
A Transaction Scoped Entity Manager is returned whenever a reference created by #PersistenceContext is resolved.
and
Every time an operation is invoked on an Entity Manager, the container proxy(the container creates a proxy around the entity manager while instantiating it ) checks for any existing Persistence Context on the JTA Transaction. If it finds one, the Entity Manager will use this Persistence Context. If it doesnt find one, then it will create a new Persistence Context and associates it with the transaction.
So the lifecycle of of entity manager is managed by your container and
we work with an instance of EntityManager, the only role of EntityManager is to determine the lifetime of the Persistence Context. It plays no role in dictating how a Persistence Context should behave. To reiterate, Persistence Context is a managed set of Entity instances. Whenever a transaction begins, a Persistence Context instance gets associated with it. And when a Transaction ends(commits for example), the Persistence Context is flushed and get disassociated with the transaction.
In the nutshell container instantiate your EntityManager by the EntityManagerFactory you provide and manage it's lifecycle but inject the proxy of EntityManager for you. The TransactionManager is responsible for creating, commiting and ... tranactions based on annotations you provide ,whenever it begins the transaction the PersistancecContext associated with it and when the tranasction ends it commites the state of PersistenceContext. The EntityManager works with PersistenceContext and if it's not provided the EntityManager creates one. The EntityManager is threadsafe as long as it holds no state and the state (PersistenceContext) is attached to current tranasction.
Hope this helps.
I'm trying to replace my CDI/EJB annotations with Spring ones. But I'm struggeling how to do it right.
This is what I have in CDI/EJB:
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
class Service {
#Inject
EntityManager em;
}
#Named
#RequestScoped
class Facade {
#Inject
Service service;
}
Now I would do the following:
#Stateless
#Transactional
#Repository
class Service {
#Inject
EntityManager em;
}
What about the stateless? What is the aquivalent in spring?
Obvious I cannot just remove this annotation, bc then I'm getting these exception:
javax.el.PropertyNotFoundException: /input.xhtml #15,30 registerButtonAction="#{facade.createNew()}": The class 'Facade$Proxy$_$$_WeldClientProxy' does not have the property ...
Further:
#Named
#Service
class Facade {
#Autowired
Service service;
}
Do I have to simply replace all #Inject annotations with #Autowired?
Is there something in Spring that takes care of EL naming, so that I can remove the #Named?
Do I have to annotate my JPA entities too?
Stateless and Stateful Beans are EJB concepts, but Spring offers similar services through Service Beans. Put the #Service annotation in your Business Logic classes, and if you want your beans to be "Stateless" or "Stateful" just configure your bean scope (like Request or Session).
Spring also has a built-in transaction management API, so your Transaction annotations may need to be changed.
Finally, Spring is compatible with many persistence frameworks including JPA. IF you want to keep JPA it is OK, and feel free to change it for another technology if you desire (maybe Hibernate, or MyBatis)
The stateless and stateful concepts are EJB; Spring doesn't have such a notion. Spring uses POJOs, without any support for stateful beans. You're on your own there.
Spring uses javax.annotation.Resource annotation; I'd prefer that to #Autowired.
Spring supports #Inject and #Named directly. No need to use #Autowired and #Component (Spring's equivalents) if you don't want to. No need to bring in #Resource either.
// This is a singleton by default, which is OK since you previously
// had it marked as stateless
#Named
#Transactional(propagation=Propagation.REQUIRES_NEW)
class Service {
#PersistenceContext // Use JPA's usual annotation
EntityManager em;
}
// You may not still need this, but if you do ...
#Named
#Scope("request")
class Facade {
#Inject
Service service;
}
In the following code, a Null pointer exception is raised when I try to call beginTransaction method. I thought that JBoss would init my transaction... apparently not :\
What am I missing ?
JBoss 5.1.0.GA
JPA 1
JDK 6
import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.transaction.UserTransaction;
public abstract class AbstractDAO {
#PersistenceUnit(unitName = "miniDS")
protected static EntityManagerFactory emf;
#Resource
protected UserTransaction t;
public AbstractDAO() {
}
protected void beginTransaction() throws Throwable {
t.begin();
}
protected void commitTransaction() throws Throwable {
t.commit();
}
protected void rollbackTransaction() throws Throwable {
t.rollback();
}
}
Your AbstractDAO does not seem to be managed. Injection only works in container managed objects. This is not specific to injection of UserTransaction, but injection in general. As result emf is null as well. Java EE specification lists following classes to be able to use injection:
Servlet: servlets, servlet filters, event listeners
JSP: tag handlers, tag library event listeners
JSF: scoped managed beans
JAX-WS: service endpoints, handlers
EJB: beans, interceptors
Managed Beans: managed beans
CDI: CDI-style managed beans, decorators
Java EE Platform: main class (static), login callback handler
Possible workaround are to move injection of resources to managed class or use JNDI lookup.
Your concrete class ConcreteDAO which extends AbstractDAO, should be an ejb, as said by Mikko Maunu and should manage itself transaction (beans that manage transaction themselves BMT), in other words:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class ConcreteDAO extends AbstractDAO {
...
}
And it be better if you inject EntityManager in your AbstractDAO, and configure JBOSS datasource to manage transaction (local-tx-datasource or xa-datasource).
you can look at JBOSS DS config at:
https://community.jboss.org/wiki/ConfigDataSources
if you want to manage transaction yourself through EntityManager, with entityManagerFactory
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
you can't use UserTransaction and the JBoss DS should be no-tx-datasource
If you inject your persistence unit, try to get the transaction through the EntityManager.
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
For more information, have a look here: https://github.com/wicketstuff/core/wiki/How-to-use-#PersistenceUnit-annotation
I am experimenting with CDI on a test application. I have a DAO which injects a container managed JTA persistence context like this:
public class TestDAO implements Serializable {
#PersistenceContext
private EntityManager entityManager;
public void insertEntity(Test test) {
entityManager.persist(test);
}
}
Now I have a CDI controller bean like this:
#Named
#SessionScoped
public class TestController implements Serializable {
#Inject
private TestDAO testDAO;
public void finishGame() {
testDAO.insertEntity(new Test(1, 2, 3));
}
}
If I run this, I receive an error in the DAO when trying to insert the entity, because there is no active transaction available. So far so good. I can solve this by making the controller bean a stateful EJB which will wrap the finishGame() in a transaction.
But let assume I don't want an EJB. As a test I annotated the finishGame() with the #TransactionAttribute annotation and it worked(the controller bean is NOT an EJB). So my question is: how does it work? Does the CDI define #TransactionAttribute for plain beans? I know that Seam Persistence Module does this, but I am not using it. Actually I added it to the project, but I removed it after, because I received awkward exceptions.
Could anyone clear my confusion? Do really CDI define #TransactionAttribute for plain beans?
P.S. I have another sort of question. I see the tendencies is to port all EJB annotations to plain beans. So will EJBs become obsolete in the future? I mean I saw in JIRA that #TransactionAttribute will be added in the future for plain beans(the task is still not resolved). So isn't this eclipsing EJBs, sort of duplicating functionality?
Best regards,
Petar
You need do define a transaction interceptor. Basically define a #Transactional annotation and intercept all methods annotated with it. In the interceptor just begin, commit or rollback the transaction. It gets more complicated when transaction propagation comes into the picture. So check if Seam doesn't have anything ready-to-use http://seamframework.org/Seam3/PersistenceModule
We have a simple stateless EJB timer that gets an instance of a spring service injected into it. The spring service has a method marked as transactional. When the EJB uses Transaction Management Type CONTAINER the spring service call results in an IllegalStateException: Operation not allowed. So we set the EJB Transaction Management Type to be BEAN and everything works as advertised. Is this normal? I was under the impression that the spring transaction management would join the CMT.
example EJB
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
#Interceptors(SpringBeanAutowiringInterceptor.class
public class TimerService {
#Autowired
IHelloService helloService;
#Schedule(second="*/1", minute="*",hour="*", persistent=false)
public void doWork(){
helloService.hello();
}
}
example spring service
#Service
public class HelloService implements IHelloService {
#Transactional
public void hello(){
}
}
Probably the problem can be fixed, if you would define propagation level for Spring transaction as SUPPORTS (default is REQUIRED). I do not remember exact value for default settings in EJB, but it seems like EJB method is not starting transaction (propagation is DEFAULT), but 'hello' tries to do so and that is causing conflict.