I am facing a weird issue when I'm trying to inject beans,
I'm always getting this stack trace:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'transactionManager' defined in class
path resource [applicationContext.xml]: Error setting property values;
nested exception is
org.springframework.beans.NotWritablePropertyException: Invalid
property 'entityInterceptor' of bean class
[org.springframework.orm.hibernate4.HibernateTransactionManager]: Bean
property 'entityInterceptor' is not writable or has an invalid setter
method. Does the parameter type of the setter match the return type of
the getter?
When I try to do this :
<bean id="transactionManager"class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="entityInterceptor" ref="auditInterceptor" />
</bean>
I did check org.springframework.orm.hibernate4.HibernateTransactionManager and it sure does has the setter for entityInterceptor and my auditInterceptor extends EmptyInterceptor which implements the methods.
I am not able to get what I am doing wrong in here?
I googled for various ways to create an interceptor for spring+hibernate 4 configuration, I don't want to use envers and I don't want to do this programmatically.
Please make sure you have added right version of Spring jar file it should be greater than version 3.2.1
Note the configuration below:
applicationContext.xml
<bean name="auditInterceptor" class="com.mypackage.AuditInterceptor" />
<bean id="myDatasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.mydbDriverClassName}"/>
<property name="jdbcUrl" value="${jdbc.mydbUrl}"/>
<property name="user" value="${jdbc.mydbUsername}"/>
<property name="password" value="${jdbc.mydbPassword}"/>
<!-- Common properties for all DS -->
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
<property name="minPoolSize" value="${jdbc.minPoolSize}"/>
<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
<property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>
<property name="preferredTestQuery" value="${jdbc.preferredTestQuery}"/>
<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDatasource"/>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="packagesToScan" value="com.mypackage" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
<property name="entityInterceptor" ref="auditInterceptor" />
</bean>
Interceptor Class
package com.mypackage;
public class AuditInterceptor extends EmptyInterceptor {
#Override
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
//method body
}
#Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
//method body
}
}
hope this will solve your problem
Related
I'd like to create a number of beans from a single class, all to be instantiated in the current application context, each based on prefixed properties in a properties file. I've given an example of what I'm trying to achieve. Any tips on how to do this without excessive code (e.g. without multiple classes, complicated factories, etc.) would be appreciated.
XML configuration:
<bean id="bean1" class="Mybean">
<property name="prefix" value="bean1"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="prefix" value="bean2"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="prefix" value="bean3"/>
</bean>
Properties File:
bean1.name=alfred
bean2.name=bobby
bean3.name=charlie
Class:
class Mybean {
#Value("${#{prefix}.name}")
String name;
}
Main Class:
public class Main {
#Autowired
List<MyBean> mybeans;
}
You can use PropertyPlaceholderConfigurer to set bean's name directly (instead of storing its prefix):
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="app.properties"/>
</bean>
<bean id="bean1" class="Mybean">
<property name="name" value="${bean1.name}"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="name" value="${bean2.name}"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="name" value="${bean3.name}"/>
</bean>
I'm trying to integrate Mybatis with spring. Here you can see my application context of Spring
<context:annotation-config />
<context:component-scan base-package="com" />
<tx:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/DB" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/com/mybatis/mybatis-config.xml" />
<!--<property name="transactionFactory" ref="springManagedTransactionFactory" />-->
</bean>
<!--
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<constructor-arg index="0" ref="dataSource" />
</bean> -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="registroClimaMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.mybatis.dao.RegistroClimaMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
First of all I have commented springManagedTransactionFactory in XML because it's giving me an exception
Error creating bean with name 'springManagedTransactionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
Here is my interface RegistroClimaMapper. I do not have any annotation here because I have defined the context:component scan.
public interface RegistroClimaMapper {
void insertarRegistroClima(RegistroClima registro) throws SQLException;
List<RegistroClima> getRegistrosClima() throws SQLException;
List<RegistroClima> getRegistrosClima(#Param("Validado") boolean Validado) throws SQLException;
}
I try to use this interface in a ManagedBean and when I'm going to use registroClimaPersistence inside a method of TablaRegistroClimaBean I get a NullPointerException
#ManagedBean(name = "tablaRegClimaBean")
#ViewScoped
public class TablaRegistroClimaBean implements Serializable {
#Autowired
private RegistroClimaMapper registroClimaPersistence;
public void setRegistroClimaPersistence(RegistroClimaMapper registroClimaPersistence) {
this.registroClimaPersistence = registroClimaPersistence;
}
}
As seen here: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#SpringManagedTransactionFactory%28%29, SpringManagedTransactionFactory has a default constructor, but none that takes a datasource. You need to pass the datasource to the newTransaction() method, but not to the constructor: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#newTransaction(javax.sql.DataSource,%20org.apache.ibatis.session.TransactionIsolationLevel,%20boolean)
Change the piece of code to
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<!--<constructor-arg index="0" ref="dataSource" />-->
</bean>
or completely remove the constructor-arg.
What NullPointerException do you get? It might come from you just defining the RegistroClimaMapper interface, but not implementing this interface in any bean. Please add a Bean that implements this interface and the Autowired annotation should work.
I have the following test:
public class Book
{
public boolean postLoadInvoked;
#PostLoad
private void onPostLoad()
{
postLoadInvoked = true;
}
}
public class MyIntegrationTest extends AbstractIntegrationTest
{
#Autowired
private BookDAO bookDAO;
#Test
public void loadBooks()
{
Book book = bookDAO.findOne(...);
assertTrue(book.postLoadInvoked);
}
}
This test passes as-is, but if I add the #Transactional annotations to the test class, it fails:
#Transactional
#TransactionConfiguration(defaultRollback=true)
public class MyIntegrationTest extends AbstractIntegrationTest
Why does configuring the test with #Transactional affect the JPA callback methods?
EDIT
The DAO is just a Spring Data repository, so has no logic:
public interface BookDAO extends
JpaRepository<Book, Long>,
QueryDslPredicateExecutor<Book> {}
The transaction manager also has a standard configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mangofactory.example</value>
</list>
</property>
<property name="persistenceUnitName" value="spring-test" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
</bean>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" />
</bean>
I'm not sure what the spring version is that you are using or if AbstractIntegrationTest is extending something, but one thing to check is that in your hierarchy your tests should extend some abstract transactional context aware spring test class.
The classes that I'm thinking about:
org.springframework.test.AbstractTransactionalSpringContextTests
org.springframework.test.AbstractTransactionalDataSourceSpringContextTests
or some jUnit flavor (depending on the version that you are using):
org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
org.springframework.test.context.junit38.AbstractTransactionalJUnit38SpringContextTests
I could think of two reasons:
#PostLoad is only executed after the transaction is committed. Unlikely.
How did you enable transactions? Did you specify proxyTargetClass = true? Otherwise, you can get weird behavior.
i have a simple question. Its possible to add dependency injection via #Ressource or #Autowired to the Hibernate Eventlistener?
I will show you my entitymanagerfactory configuration:
<bean id="entityManagerFactory" class="org.hibernate.ejb.EntityManagerFactoryImpl">
<qualifier value="entityManagerFactory" />
<constructor-arg>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager">
<bean
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManagerr">
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mis" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaProperties" ref="jpa.properties" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database">
<util:constant
static-field="org.springframework.orm.jpa.vendor.Database.POSTGRESQL" />
</property>
<property name="showSql" value="true" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
At the moment i register my listener via jpa.properties,
hibernate.ejb.event.load=com.example.hibernate.events.LoadEvent
but in this case i have no spring injection in my listener. I found a solution, but this use the sessionFactory and not the entitymanager oder can i modifiy the sessionfactory in my context? Hopefully someone have a nice idea or solutionhow to deal with this problematic!
Big thanks!
If you used SessionFactory, this would be the configuration:
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- Stripped other stuff -->
<property name="eventListeners">
<map>
<entry key="pre-load">
<bean class="com.mycompany.MyCustomHibernateEventListener1" />
</entry>
<entry key="pre-persist">
<bean class="com.mycompany.MyCustomHibernateEventListener2" />
</entry>
</map>
</property>
</bean>
But since you are using JPA, I'm afraid you need to use AOP as outlined in this thread
Or you can
store the ApplicationContext in a ThreadLocal or a custom holder class and expose it through a static method
have a base class for your listeners something like this:
Base class:
public abstract class ListenerBase{
protected void wireMe(){
ApplicationContext ctx = ContextHelper.getCurrentApplicationContext();
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
}
Now in your lifycycle methods call wireMe() first.
Update:
Here is a sample implementation of ContextHelper:
public final class ContextHelper implements ApplicationContextAware{
private static final ContextHelper INSTANCE = new ContextHelper();
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
public static ApplicationContext getCurrentApplicationContext(){
return INSTANCE.applicationContext;
};
public static ContextHelper getInstance(){
return INSTANCE;
}
private ContextHelper(){
}
}
Wire it in your Spring Bean configuration like this:
<bean class="com.mycompany.ContextHelper" factory-method="getInstance" />
My DAO's are going to extend the HibernateDaoSupport class that spring provides.
Now I need to:
setup my database connection in web.xml
Tell spring I am using annotations for hibernate mapping?
wire the session to the HibernateDaoSupport object.
The doc's show a sample xml:
<beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
</beans>
So the 'mydatasource' configures the connection to the database, and the mySessionFactory sets up the session.
What I am confused with is, where in the code are these beans being used?
I want to create a GenericDaoImpl that extendsHibernateDaoSupport. I will then create EntityDaoImpl that extend GenericDaoImpl.
Just confused as to where 'mydatasource' and 'mysessionFactory' are used internally. Shouldn't they both be properties to HibernateDaoSupport?
Shouldn't they both be properties to
HibernateDaoSupport?
Well, SessionFactory should. The DAO won't need the DataSource, since that's used internally by the SessionFactory. Your own code should have no need for the raw DataSource, and so should not have to be injected with it.
Your DAOs (which extend HibernateDaoSupport) need to injected with the SessionFactory bean, e.g.
public class DaoA extends HibernateDaoSupport {
// business methods here, that use getHibernateTemplate()
}
public class DaoB extends HibernateDaoSupport {
// business methods here, that use getHibernateTemplate()
}
<bean id="daoA" class="DaoA">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="daoB" class="DaoB">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>