I am trying to implement method described here, but can't make it work.
There are no errors during compilation, but the interceptor never fired.
DAO:
public class GeneralInvoicesDAO {
#Autowired
private SessionFactory sessionFactory;
#Autowired
private Interceptor entityInterceptor;
#Transactional
public void update(GeneralInvoice object) {
Session session = SessionFactoryUtils.getSession(sessionFactory, entityInterceptor, null);
session.saveOrUpdate(object);
}
}
The intercepter class:
public class NewEntityInterceptor extends EmptyInterceptor implements Interceptor {
/**
*
*/
private static final long serialVersionUID = 2914362528125673753L;
#Override
public Boolean isTransient(Object n) {
Logger logger = Logger.getLogger(getClass().getName());
try {
logger.warn("test");
Boolean result = Boolean.FALSE;
BaseEntity entity = (BaseEntity) n;
if (entity.getId() <= 0L) {
entity.setId(null);
result = Boolean.TRUE;
}
logger.warn(result.toString());
return result;
}
catch (Exception e) {
e.printStackTrace();
return super.isTransient(n);
}
}
}
Config:
<bean id="newEntityInterceptor" class="de.crm.interceptor.NewEntityInterceptor" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="entityInterceptor" ref="newEntityInterceptor" />
</bean>
What's wrong?
Thank you
Few observations from you code
You are NOT overriding any of the methods in EmptyInterceptor. Check out this link with a sample interceptor example.
EmptyInterceptor provides the default implementations of an entity life cycle events which you can intercept. You need to override the method of your interest.
I am not sure if transactionManager needs any reference to the interceptor. Its purely a hibernate thing. You can do away with it. Interceptors are needed either with session or session factory (you are using session level interceptor).
Related
I have several methods with spring #Transactional in my project as following:
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW)
public void addMember(InputParam input)
{
// do somthing...
}
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW)
public void blockMember(InputBlockParam param)
{
// do somthing...
}
Then I set different timeout per method as following:
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW,timeout = 40)
public void addMember(InputParam input)
{
// do somthing...
}
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW, timeout = 20)
public void blockMember(InputBlockParam param)
{
// do somthing...
}
I want in last step set timeout as configurable by a properties file but I don't know what.
Is there any solution for set timeout in spring Transactional annotaion configurable or dynamically?
EDIT:
I define sys.tx.mngr in spring context file as following:
<bean id="sys.tx.mngr" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="sys.tx.mngr" />
Or is there alternative way for define timeout in spring context file per method?
It can be done on following ways only :-
a) Using Reflection.
b) Using Instrumentation.
c) Using TransactionTemplate (Programatically transaction).
For (a) & (b) you can have your class like following :-
public class Test implements InitializingBean {
#Autowired
private Environment env;
public void afterPropertiesSet() throws Exception {
System.out.println("Sample prop 1 value : "+env.resolvePlaceholders("${prop1.value}"));
//Code to set/modify Transactional annotation "timeout"
// attribute values for all methods
}
}
Link on how to set/modify values can be found here
Modify field annotation value dynamically
Modify a class definition's annotation string parameter at runtime
For (c) you can have config like :-
public class MemberDaoImpl {
#Autowired
private Environment env;
#Autowired
private TransactionTemplate transactionTemplate;
public void addMember(InputParam input) {
transactionTemplate.setTimeout(Integer.parseInt(env.resolvePlaceholders("${addmember.timeout}")));
// do somthing...
}
}
<bean id="memberDao" class="com.xxx.impl.MemberDaoImpl">
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="sys.tx.mngr" />
</bean>
</property>
</bean>
<bean id="sys.tx.mngr" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
I need to inject EntityManager in EntityListener class so that I can perform CRUD operation on it.
POJO:
#Entity
#EntityListner(AuditLogging.class)
class User
{
//Getter / setter of properties
}
AuditLogging (Listner class)
public class AuditInterceptor
{
#PersistenceContext
EntityManager entityManager;
public void setEntityManager(EntityManager entityManager)
{
this.entityManager = entityManager;
}
#PrePersist
public void prePersist(Object obj)
{
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
JDBC-CONFIg.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.XXXXX.entity" />
<property name="jpaProperties">
</bean>
<!-- Datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driver.classname}" />
<property name="jdbcUrl" value="${jdbc.url}" />
</bean>
<!-- transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
EntityListener is not managed by any of the container.EntityListeners are instanciated by JPA, so Spring does not have an opportunity to inject EntityManager.
My question is, how we can inject inject EntityManager in EntityListener class so that I can perform CRUD operation on it ???
I have faced a similar problem where I was trying to create history records for an entity using EntityListeners.
In order to resolve this problem, I have created utility class BeanUtil with a static method to get the bean and used this util class to get bean inside my Entitylistener class
#Service
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Now we can call BeanUtil.getBean() to get the bean of any type
public class FileEntityListener {
#PrePersist
public void prePersist(File target) {
perform(target, INSERTED);
}
#Transactional(MANDATORY)
private void perform(File target, Action action) {
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
}
}
We can use this BeanUtil class to get any spring managed bean from anywhere, To know more you can read my article JPA Auditing: Persisting Audit Logs Automatically using EntityListeners.
Anyways, I got this done by getting entityManager reference from EntityManagerFactory bean which is configured in my jdbc-config.xml. But again this is not what I wanted. I wanted to work around with #PersistenceContext.
#Autowired
EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
entityManager=entityManagerFactory.createEntityManager();
this.entityManagerFactory = entityManagerFactory;
}
Here are few notes that we need to keep in mind:
We can't inject an EntityManager into an EntityListener (through
#PersistenceContext). EntityListener is not managed by any of the
containers
#PersistenceContext class cannot be static. So we cant
attain the instance while class loading.
EntityListeners are
instantiated by JPA, so Spring does not have an opportunity to
inject EntityManager
Well, the first solution which came into my mind is a little "hack", but should work.
public class AuditInterceptor {
static setEntityManager emf;
#Autowired
public void setEntityManagerFactory(EntityManager emf) {
AuditInterceptor.emf = emf;
}
#PrePersist
public void prePersist(Object obj) {
EntityManager entityManager = emf.getEntityManager();
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
}
}
Inside of your code use EntityManager entityManager = emf.getEntityManager()
Declare your AuditInterceptor as a spring bean (#Component with component-scan or define AuditorInterceptor as a bean)
I used a ThreadLocal to pass the Spring Application Context which contains EntityManager around. Though I am not sure if it is safe Is it safe to pass in the Spring Application Context into a ThreadLocal associated with a request? but so far it is working for me.
The listener can be modified to have autowiring like this. However this needs to be done on on the handlers and not the constructor (doing it on the constructor seems less predictable). You are also not limited to the EntityManager but you have access to the whole context.
#Autowired
private EntityManager entityManager;
#Autowired
private MyDao myDao;
#PrePersist
public void pre() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
Objects.requireNotNull(myDao);
myDao.doSomething();
}
I understand we need to keep #Transactional boundaries as short as possible. Here is the code :
I am using userDAO object through Spring dependency injection :
private static ApplicationContext context ;
private UserDAO userDAO;
public TransactionsTest() {
userDAO = (UserDAO) context.getBean("userDAO");
}
I am calling testSaveUserAccounts() from TransactionsTest class trying to use userDAO for insertion/updation of data.
Case 1:
#Transactional
public void testSaveUserAccounts() {
UserAccounts userAccounts = new UserAccounts();
userAccounts.setCommunityId(10L);
userDAO.saveObject(userAccounts);
}
// This method is inside UserDAO
public void saveObject(Object object) {
entityManager.merge(object);
}
Case 2:
#Transactional
public void testSaveUserAccounts() {
UserAccounts userAccounts = new UserAccounts();
userAccounts.setCommunityId(10L);
userDAO.saveObject(userAccounts);
}
// This method is inside UserDAO
#Transactional(propagation=Propagation.REQUIRED)
public void saveObject(Object object) {
entityManager.merge(object);
}
Spring Context :
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceLocal" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="spring-jpa" />
</bean>
UserDAO :
#Repository
public class UserDAO extends BaseDAO {
#Transactional(propagation=Propagation.REQUIRED)
public void saveObject(Object object) {
entityManager.merge(object);
}
}
BaseDAO :
public abstract class BaseDAO {
protected EntityManager entityManager;
protected HashMap<String,Long> eventIdMap = new HashMap<String,Long>();
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this. entityManager = entityManager;
}
public <T> T getById(final Class<T> clazz, final Serializable id) {
T object = clazz.cast(entityManager.find(clazz, id));
return object;
}
#Transactional
public Object save(Object ob) {
Object object = entityManager.merge(ob);
return object;
}
#Transactional
public void persist(Object ob) {
entityManager.persist(ob);
}
#SuppressWarnings("unchecked")
public <T> ArrayList<T> getAll(final Class<T> clazz) {
String hqlQuery = "from "+ clazz.getSimpleName();
ArrayList<T> list = (ArrayList<T>)entityManager.createQuery(hqlQuery).getResultList();
return list;
}
}
I have been experimenting around several transactional boundaries REQUIRED, REQUIRES_NEW, SUPPORTS, etc but couldn't confidently make out as to why Case 1 (when method2 is called which is inside transactional boundary of method1) does not merges the data, while, this is solved in Case 2.
Why do I need to specify #Transactional in inner methods as well when already I have marked calling function within Transaction boundary ?
Your transaction test class is not a Spring Bean that is why Case 1 does not work. Spring needs to detected that a method has #Transactional on it and it does that when spring registers the bean with the spring bean factory.
Also keep in mind that the if you are doing Proxy Based AOP calls within the same bean will not be caught by the transaction aspect unless you use AspectJ load time weaving or AspectJ compile time weaving.
Also putting #Transactional on your Dao's is not a really a good idea because transaction boundaries are best marked at the service layer. The reason why is that a particular service method might need to interact with multiple Dao's and you would want those Dao's actions to be part of the tx started by the service layer, rather than having to analyze the Dao's to see what the propagation behavior is.
Can you post the complete code for the test class?
#Transactional does nothing locally, it only has an effect when called from a different service. In other words, you have to leave your current context for transaction annotations to do anything. so calling method 1 is identical in both cases, Case 2 only does anything if method2 is called from another service.
I have:
#Component
class MyDecorator{
private Cache cache;
/*
some wrapped methods like get put remove
*/
}
Is it possible to autowire MyDecorator in different places with different cache?
I can configure XML like this:
<bean id="id1" class="MyDecorator ">
<property name="cache" value="Cache1" />
</bean>
<bean id="id2" class="MyDecorator ">
<property name="cache" value="Cache2" />
</bean>
But is there more elegance way without addition of xml configs, only with annotation?
Correct code should be
#Configuration
public class AppConfig {
#Bean
public MyAdapter adaptedCache2() {
return new MyAdapter (cache1);
}
#Bean
public MyAdapter adaptedCache2() {
return new MyAdapter (cache2);
}}
according to specs will be generated two beans adaptedCache1 and adaptedCache2
and now i can
autowire those beans with qualifiers adaptedCache1 and adaptedCache2
With Java configuration (Spring 3.1) you can write:
#Bean
public MyDecorator decoratedCache1() {
return new MyDecorator(cache1);
}
#Bean
public MyDecorator decoratedCache2() {
return new MyDecorator(cache2);
}
Of course in this case MyDecorator does not need #Component:
#Component
class MyDecorator{
private final Cache cache;
public MyDecorator(Cache cache) {
this.cache = cache;
}
}
It doesn't seem to be working right now. I get a
java.lang.NullPointerException
I have a class that implements an interface
public class LearnerDao implements BaseDao {
private BaseDao dao;
public void setDao(BaseDao dao) {
this.dao=dao;
}
.
.
.
}
This is my wiring
<bean id="pm" factory-bean="pmf" factory-method="getPersistenceManager"
scope="prototype"></bean>
<bean id="learnerDao" class="com.hardwire.dao.impl.LearnerDao">
<property name="pm" ref="pm"></property>
</bean>
<bean id="twitterUserDao" class="com.hardwire.dao.impl.TwitterUserDao">
<property name="pm" ref="pm"></property>
</bean>
<bean id="learnerService" class="com.hardwire.service.LearnerService">
<property name="dao" ref="learnerDao"></property
</bean>
Here's my learnerService
public class LearnerService {
private static final Logger log =
Logger.getLogger(LearnerService.class.getName());
private BaseDao dao;
.
.
.
public void insert(Learner learner){
if (dao==null){
log.info("dao is null");
}
else {
log.info("dao is not null");
}
dao.insert(learner);
}
public void setDao(BaseDao dao) {
this.dao = dao;
}
It's only learnerDao that implements BaseDao. On the other hand, bean twitterUserDao does not. I'd like to note that twitterUserDao was injected just okay but learnerDao wasn't.
The logs show that learnerDao is null. So I was wondering if this had anything to do with learnerDao implementing an inteface.
Nope, you can definitely do that. Note that you're trying to set a pm property in learnerDao, but you haven't shown anything setting the dao property. Could that be the problem?
I finally found where everything's going wrong. I had this bug of code to kill in a Controller that has learnerService as its dependency:
learnerService = new LearnerService();
Laughing my ass off right now! :))