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?
Related
In my application,we bind the datasource through the JNDIlook up using below code:
<bean id="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/jboss/datasources/efmDS</value>
</property>
</bean>
Dao has code like below:
#Autowired
#Qualifier("jndiDataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
Now I am having problem while running Junit test case.
I am testing a service method which is annotated with #Transactional.
This service method internally calls some dao method which I have already mocked using mockito but I am facing issues as when transaction is getting started it tries to fetch connection from datasource which is not present and throws communicationslinkfailure exception
How can I mock datasource in this case ? or any other alternative to solve the issue is also appreciated ?
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);
}
I have something like this:
class MyBean {
#Autowired
#Qualifier("jdbcTemplate")
#BeanProperty
var jdbcTemplate : JdbcTemplate = null
}
Spring complains that it can't find a bean of type JdbcTemplate and refuses to autowire. My spring.xml has:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
If I change the type of jdbcTemplate in MyBean from JdbcTemplate to SimpleJdbcTemplate then it works. My question is why is it apparently ignoring the Qualifier annotation? Am I doing something wrong?
It has nothing to do with #Qualifier. SimpleJdbcTemplate is not a subclass of JdbcTemplate, therefore it cannot be injected into a field of type JdbcTemplate.
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.
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.