Question on required persistence/transaction configuration when not using annotations - spring

We are using JPA/Hibernate and the Transactions via AOP, however, we are not using any annotations (all JPA configuration is in persitence and orm files and transactions are solely through AOP). The only annotation we are using is on the setEntityManager:
/**
* Sets the entity manager.
*
* #param entityManager
* the new entity manager
*/
#PersistenceContext
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
So do I need to use the following configuration capabilities if I am not using annotations for transactions or for JPA mappings?
<tx:annotation-driven transaction-manager="GlobalDataTransactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
Thanks for your help....jay

You need the PersistenceAnnotationBeanPostProcessor, but you don't need the <tx:annotation-driven>:
<tx:annotation-driven /> registers a proxy around annotated classes. Since you have xml config, you already have the transaction proxies
The post-processor handles the #PersistenceContext annotations on DAOs.

Related

Spring equivalent of #Stateless EJB with multiple #PersistenceContext

I've been banging my head on the wall for the past couple of days trying to get this to work but I've not been able to.
I wrote a JPA EntityManagerProvider recently using EJB:
EntityManagerProviderBean.java
#Stateless
public class EntityManagerProviderBean {
#PersistenceContext(unitName="PU1")
private EntityManager entityManager1;
#PersistenceContext(unitName="PU2")
private EntityManager entityManager2;
public EntityManager getEntityManager() {
return (...) ? entityManager1: entityManager2;
}
}
And then of course I can inject the EJB wherever needed like this:
UserFacade.java
#Stateless
public class UserFacade {
#EJB
private EntityManagerProviderBean emProvider;
private EntityManager em = emProvider.getEntityManager();
...
}
Now I'm trying to do something similar using Spring, using annotations, and without doing anything in XML. I can't seem to figure out a way to inject the EntityManager. Anything that I do leads to a NullPointerException. For example, I tried to inject the EntityManager manually without relying on my EntityManagerProviderBean, like this:
UserFacadeSpring.java
public class UserFacadeSpring {
#PersistenceContext(unitName="PU1")
private EntityManager em;
...
}
But this gives me a NullPointerException. So the EntityManager is not being injected at all and I'm not sure what's wrong.
So two questions basically:
How can I inject the EntityManager using Spring?
How can I use my existing EntityManagerProviderBean EJB in Spring? What modifications do I need to make?
Any help in this matter will be greatly appreciated. As you can tell I'm a complete noob to Spring. I tried to read the guide but everything's flying over my head at the moment. I actually did try to do something half-baked but it didn't work either (I either get NullPointerException or BeanNotFoundException, I must have used every combination of #Component, #Bean, #Autowired annotations I think!):
EntityManagerProviderSpring.java
#Component
public class EntityManagerProviderSpring {
#PersistenceContext(unitName="PU1")
private EntityManager entityManager1;
#PersistenceContext(unitName="PU2")
private EntityManager entityManager2;
#Bean
public EntityManager getEntityManager() {
return (...) ? entityManager1: entityManager2;
}
}
Main.java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(EntityManagerProviderSpring.class);
EntityManagerProviderSpring emProvider = context.getBean(EntityManagerProviderSpring.class);
EntityManager em = emProvider.getEntityManager();
...
}
Thanks!
EDIT: I'm using Hibernate with JPA and the following is my persistence.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db1?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.user" value="pu1_username"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="pu1_pwd"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
</properties>
</persistence-unit>
<persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL">
...
</persistence-unit>
</persistence>
To have the exact same functionality on dependency injection level, it is impossible to map stateless ejb bean to a spring bean.
EJB #Singleton -> Spring #Component (or #Service or #Controller or #Repository)
EJB #Stateful -> Spring #Component#Scope("prototype") (or #Service#Scope("prototype") or #Controller#Scope("prototype") or #Repository#Scope("prototype"))
EJB #Stateless -> DOES NOT EXIST IN SPRING.
Stateless beans are very handy for this multiple persistence contexts... However, since Spring doesn't offer stateless bean. You have to use custom Spring setup to apply multiple persistence context. It won't work with only persistence.xml like EJB, unfortunately :(.
So to answer your questions:
Read Spring doc... Plenty of examples everywhere. Shortly, In Spring 4 Java Config you can use #EnableTransactionManagement, a transaction manager and an entity manager factory per persistence context.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/ejb.html. This is how you do it. Not a nice way since using jndi, but it is a solution...

How entity manager is injected from localcontainerEntityManagerFactoryBean

I was searching for how entity manager is injected into DAO classes when I configure LocalContainerEntityManagerFactoryBean class in spring.
class OrderDAOImpl {
#PersistenceContext
private EntityManager entityManager
//....DAO Methods...
}
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
.....
</bean>
From this bean, how spring creates entityManager.
I was searching the same reason for hibernate's session factory and I found Here that getObject method will inject sessionFactory. But same is not the case with LocalContainerEntityManagerFactoryBean. Can some one please help me understand how this entityManager is injected in JPA?

Is it possible to use SpringData-JPA with a hibernate4.LocalSessionFactoryBean?

I am already using Hibernate 4 directly with a LocalSessionFactoryBean and a SessionFactory in my code.
I would now like to include Spring-Data-JPA in my code.
But Spring-Data needs an EntityManagerFactory to work, which can be configured through a LocalContainerEntityManagerFactoryBean. Can these Beans LocalSessionFactoryBean and LocalContainerEntityManagerFactoryBean coexist in one Spring project?
(Or can one be adapted by the other?)
What is the best practice?
Although they can coexists it will be problematic especially if you want to have them participate in the same transaction. However if you switch your logic around and configure a LocalContainerEntityManagerFactoryBean instead of a LocalSessionFactoryBean you can use the HibernateJpaSessionFactoryBean to get access to the underlying SessionFactory.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- Your properties here -->
</bean>
<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Now you have both and can participate in the same transaction.
This solution is also documented in the Spring Data JPA reference guide in the FAQ section.
#Autowired
private EntityManager entitymanager;
public List<SpBooking> list() {
// #SuppressWarnings("unchecked")
System.out.println("******************************");
// #SuppressWarnings("unchecked")
List<SpBooking> listUser = (List<SpBooking>)((Session)entitymanager.getDelegate())
.createCriteria(SpBooking.class)
.list();
for (SpBooking i:listUser)
System.out.println("------------------"+i.getBookingId());
return listUser;
}
And as of JPA 2.1, EntityManagerFactory.unwrap(java.lang.Class) provides a nice approach, documented here: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/vendor/HibernateJpaSessionFactoryBean.html
#Bean
public SessionFactory sessionFactory(#Qualifier("entityManagerFactory") EntityManagerFactory emf) {
return emf.unwrap(SessionFactory.class);
}

Using #Repository-style exception translation from Spring Java configuration

If I want to declare a bean using Spring 3's Java-based configuration, I can do this:
#Configuration
public class MyConfiguration {
#Bean
public MyRepository myRepository() {
return new MyJpaRepository();
}
}
But, since I can't use the #Repository annotation in this context, how do get Spring to perform exception translation?
Declare your MyJpaRepository class as a repository:
#Repository
public class MyJpaRepository {
...
}
And make sure you have your annotations discoverable by setting up the component-scan element in your Spring configuration:
<context:component-scan base-package="org.example.repository"/>
Since you do not want your repository included in the annotation scan per your comments, filter it out either by excluding all #Repository annotations or your particular class(es) or package. There is an example of this in the documentation:
<context:component-scan base-package="org.example.repository">
<!-- use one or the other of these excludes, or both if you *really* want to -->
<context:exclude-filter type="regex" expression="*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
The Spring 3.0 documentation describes this configuration in more detail in section 3.10.
By configuring your class as a Repository, it will be designated as one when you pull it out as a Bean in your Configuration class.

Ability to switch Persistence Unit dynamically within the application (JPA)

My application data access layer is built using Spring and EclipseLink and I am currently trying to implement the following feature - Ability to switch the current/active persistence unit dynamically for a user. I tried various options and finally ended up doing the following.
In the persistence.xml, declare multiple PUs. Create a class with as many EntityManagerFactory attributes as there are PUs defined. This will act as a factory and return the appropriate EntityManager based on my logic
public class MyEntityManagerFactory {
#PersistenceUnit(unitName="PU_1")
private EntityManagerFactory emf1;
#PersistenceUnit(unitName="PU_2")
private EntityManagerFactory emf2;
public EntityManager getEntityManager(int releaseId) {
// Logic goes here to return the appropriate entityManeger
}
}
My spring-beans xml looks like this..
<!-- First persistence unit -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emFactory1">
<property name="persistenceUnitName" value="PU_1" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager1">
<property name="entityManagerFactory" ref="emFactory1"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager1"/>
The above section is repeated for the second PU (with names like emFactory2, transactionManager2 etc).
I am a JPA newbie and I know that this is not the best solution. I appreciate any assistance in implementing this requirement in a better/elegant way!
Thanks!
First of all thanks to user332768 and bert. I tried using AbstractRoutingDataSource as mentioned in the link provided by bert, but got lost trying to hook up my jpa layer (eclipselink). I reverted to my older approach with some modifications. The solution looks cleaner (IMHO) and is working fine. (switching database at runtime and also writing to multiple databases in the same transaction)
public class MyEntityManagerFactoryImpl implements MyEntityManagerFactory, ApplicationContextAware {
private HashMap<String, EntityManagerFactory> emFactoryMap;
public EntityManager getEntityManager(String releaseId) {
return SharedEntityManagerCreator.createSharedEntityManager(emFactoryMap.get(releaseName));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
Map<String, LocalContainerEntityManagerFactoryBean> emMap = applicationContext.getBeansOfType(LocalContainerEntityManagerFactoryBean.class);
Set<String> keys = emMap.keySet();
EntityManagerFactory entityManagerFactory = null;
String releaseId = null;
emFactoryMap = new HashMap<String, EntityManagerFactory>();
for (String key:keys) {
releaseId = key.split("_")[1];
entityManagerFactory = emMap.get(key).getObject();
emFactoryMap.put(releaseId, entityManagerFactory);
}
}
}
I now inject my DAO's with an instance (singleton) of MyEntityManagerFactoryImpl. The dao will then simply call createSharedEntityManager with the required release and will get the correct EntityManager for that database. (Note that i am now using application managed EntityManager and hence i have to explicitly close them in my dao)
I also moved to jta transaction manager (to manage transaction across multiple databases)
This is how my spring xml looks like now.
...
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="em_Rel1">
<property name="persistenceUnitName" value="PU1" />
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="em_Rel2">
<property name="persistenceUnitName" value="PU2" />
</bean>
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="jtaTransactionManager">
</bean>
<tx:annotation-driven transaction-manager="jtaTransactionManager"/>
....
Cheers! (comments are welcome)
I am not sure if this is a clean method. Instead of declaring the enitiymanagerfactory multiple times, we can use the spring application context to get the entitymanagerfactory declared in the spring application.xml.
hm = applicationContext.getBeansOfType(org.springframework.orm.jpa.LocalEntityManagerFactoryBean.class);
EntityManagerFactory emf = ((org.springframework.orm.jpa.LocalEntityManagerFactoryBean) hm.get("&emf1")).getNativeEntityManagerFactory();
EntityManagerFactory emf2 = ((org.springframework.orm.jpa.LocalEntityManagerFactoryBean) hm.get("&emf2")).getNativeEntityManagerFactory();
This is something i need to do in the future too, for this i have bookmarked Spring DynamicDatasourceRouting
http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/
As far as i understand, this is using one PU, which gets assigned different DataSources. Perhaps it is helpful.

Resources