How to register a Hibernate Empty Interceptor in Spring's applicationContext.xml - spring

How do I easily hook up a Hibernate EmptyInterceptor (an Audit Interceptor) in a Spring app's applicationContext.xml?
No annotations are supported, this is an older Spring app.
My Hibernate Empty Interceptor is
public class AuditInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 1L;
#Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
// TODO Auto-generated method stub
System.out.println("onDelete intercepted");
super.onDelete(entity, id, state, propertyNames, types);
}
#Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
// TODO Auto-generated method stub
System.out.println("onFlushDirty intercepted");
return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}
#Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
// TODO Auto-generated method stub
System.out.println("onSave intercepted");
return super.onSave(entity, id, state, propertyNames, types);
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${jdbc.datasource}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.min_size">1</prop>
<prop key="hibernate.c3p0.timeout">5000</prop>
<prop key="hibernate.c3p0.max_statements">100</prop>
<prop key="hibernate.c3p0.idle_test_period">300</prop>
<prop key="hibernate.c3p0.acquire_increment">2</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>

The following worked. Thanks for the tip
<!-- First define the bean -->
<bean id="auditInterceptor" class="mypackage.AuditInterceptor" />
<!-- Now add entityInterceptor property in sessionFactory Bean, referring to this bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="entityInterceptor" ref="auditInterceptor" />

Related

Exception Illegal Argument - unknown entity JPA - Additional package to scan for entities in application-context.xml is not taken into consideration

I am working on a Spring application which has a persistence unit configured in the application-context.xml. I need to add an additional package in in order to use new entities.
Even though this part of the persistence.xml file looks like below, my entities from the additional package are not seen by the application and I get an exception saying that the entity is unknown.
<bean id="transactionManager_students" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryStudents" />
<qualifier value="clientTransaction" />
</bean>
<bean id="entityManagerFactoryStudents"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource_College" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan">
<list>
<value>com.load.model</value>
<value>com.students.entity</value>
</list>
</property>
<property name="persistenceUnitName" value="unit_stud" />
<property name="jpaProperties">
<props>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>  
I also have to mention that I annotated the entities with #Entity and in the class where I am operating on the entities I have this ( the row with em.persist(student) is giving me the error )
#PersistenceContext(unitName = "unit_stud")
public EntityManager em;
public Student student;
#Transactional(value = "clientTransaction", propagation = Propagation.REQUIRED)
public long persistStudentObject() {
long studentId = 0;
try
{
logger.debug("Start Persisting...");
em.persist(student);
// unique ID
studentId = student.getId();
logger.debug("Persisting OK...");
}
catch (PersistenceException persistenceException)
{
logger.error("PersistenceException occur", persistenceException);
}
}
return studentId ;
}
The entity:
package com.students.entity;
#Entity
#Table(name = "STUDENTS", schema = "DEMO", catalog = "")
public class Student{
private long id;
private String firstname;
private String name;
private String streetnumber;
private String zipcodecity;
Can anyone help me? I do not know what to do in order to make my entities visible.

HibernateTemplate object is null while saving data using spring MVC+hibernate

I'm trying to insert data into table using Spring MVC+Hibernate. Table is geting creating but code throwing exception at template.save() method calling in CompanyDao file. Please help to solve this.
I have tested if company object is null but company object having all data but template in null.
File: CompanyDao.java
import org.springframework.orm.hibernate5.HibernateTemplate;
public class CompanyDao {
HibernateTemplate template;
public void setTemplate(HibernateTemplate template) {
this.template = template;
}
//method to save Company
public void saveCompany(Company c){
if(c!=null) {
template.save(c);
}
else {
System.out.print("company object is null");
}
}
}
ApplicationContext.xml
<bean id="mysessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>company.hbm.xml</value>
<!-- <value>address.hbm.xml</value> -->
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="mysessionFactory"></property>
</bean>
<bean id="template" class="dao.CompanyDao">
<property name="template" ref="hibernateTemplate"></property>
</bean>
File Controller:
#RequestMapping("/submitCompanyRegForm")
public ModelAndView submitCompanyRegForm(#ModelAttribute("companyMo") Company comp)
{
CompanyDao companydao = new CompanyDao();
companydao.saveCompany(comp);
ModelAndView model = new ModelAndView("submitcompanyreg");
return model;
}

Spring Data JPA + Hibernate : Inject Catalog/Schema at runtime in to JPA Entities

We have a scenario where in the catalog/schema combination is different for the entity classes inside certain package from the default one used by all others. I am trying to set Catalog and Schema on #Table annotation using PersistenceUnitPostProcessors callback at runtime using javaassist as below.
The issue: The added member values on javaassist annotation are NOT getting reflected on to the actual class associated with it. Please help me in finding the wrong lines of code; OR if there are other ways to achieve this, more than happy to know.
Note: I do not want to create a separate EntityManagerFactory for each catalog/schema combination - it is not really required in our case as the datasource is same.
related content in spring context :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
<bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mainUnit" />
<property name="packagesToScan" value="com.mycompany.lob.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitPostProcessors">
<list>
<bean class="com.mycompany.lob.jpa.CustomPersistenceUnitPostProcessor"/>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SqlmxDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">100</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.default_schema">DEFAULT_SCHEMA</prop>
<prop key="hibernate.default_catalog">DEFAULT_CATALOG</prop>
</props>
</property>
</bean>
PersistenceUnitPostProcessors callback :
public class CustomPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
#Value("${user.schema}")
private String userSchema;
#Value("${user.catalog}")
private String userCatalog;
private static final Logger LOGGER = LoggerFactory.getLogger(CustomPersistenceUnitPostProcessor.class);
#SuppressWarnings("unchecked")
#Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
LOGGER.info("MutablePersistenceUnitInfo : {} ",pui);
List<String> jpadomains = pui.getManagedClassNames();
for (Iterator<?> iterator = jpadomains.iterator(); iterator.hasNext();) {
String clazzName = (String) iterator.next();
if(clazzName.startsWith("com.mycompany.lob.domain.user")){
try {
//modify annotation attributes using JavaAssist
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(clazzName);
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag);
if(annotationsAttribute!=null){
//Get hold of #Table annotation
Annotation tableAnnotation = annotationsAttribute.getAnnotation("javax.persistence.Table");
if(tableAnnotation!=null){
tableAnnotation.addMemberValue("catalog", new StringMemberValue(userCatalog, constPool));
tableAnnotation.addMemberValue("schema", new StringMemberValue(userSchema, constPool));
annotationsAttribute.addAnnotation(tableAnnotation);
LOGGER.debug("Schema-Table : {} - {} ", ((StringMemberValue)tableAnnotation.getMemberValue("schema")).getValue(),
((StringMemberValue)tableAnnotation.getMemberValue("name")).getValue() );
//write the file back
ctClass.writeFile();
}
}
} catch (Exception e) {
LOGGER.error("Schema/Catalog could not be altered for {} ",clazzName);
}
}
}
}
}
Simple answer:
19. Multitenancy
Complex catalog mapping:
interface PhysicalNamingStrategy in Hibernate v5 is helpful.
public interface PhysicalNamingStrategy {
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment);
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment);
....
}
Check the Example 2. Example PhysicalNamingStrategy implementation in Hibernate 5 User Guide and how to config it

Spring + hibernate 3 "No Hibernate Session bound to thread" But i have a transaction manager configured

i have this problem: "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here". I'm using spring + hibernate 3. I already had checking this in other questions, but they don´t solve my problem. Here, my applicationContext of Spring.
`<bean id="ServGenerico" class="servico.AbsServicoGenerico" />
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
p:driverClass="${jdbc.driver}" p:jdbcUrl="${jdbc.url}" p:user="${jdbc.username}"
p:password="${jdbc.password}" p:max PoolSize="10" p:minPoolSize="5" p:maxStatements="0" destroy-method="close">
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="dao" />
<context:component-scan base-package="dao.impl" />
<context:component-scan base-package="servico" />
<bean id="grupoDeAcaoDao" class="dao.impl.GrupoDeAcaoDao" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="dados" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
<!-- <prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</prop>
--><!-- <prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.min_size">2</prop>
<prop key="hibernate.c3p0.timeout">5000</prop>
<prop key="hibernate.c3p0.max_statements">10</prop>
<prop key="hibernate.c3p0.idle_test_period">3000</prop>
<prop key="hibernate.c3p0.acquire_increment">2</prop> -->
<!-- <prop key="hibernate.transaction.jta.platform">
org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform
</prop> -->
</props>
</property>
</bean>`
My service
#Service
#Transactional
public class ServGrupoDeAcao extends AbsServicoGenerico<GrupoDeAcao>
{
public ServGrupoDeAcao()
{
super();
setDao(new GrupoDeAcaoDao());
}
public ServGrupoDeAcao(Class<?> clazz)
{
super(clazz);
}
/*#Autowired
#Qualifier("grupoDeAcaoDao")
public void setDao(GrupoDeAcaoDao dao)
{
super.setDao(dao);
}*/
}
And my DAO
#Repository
#Transactional
public class GrupoDeAcaoDao extends AbsDao<GrupoDeAcao, Long>
{
#Override
public boolean equals(Object object)
{
// TODO Auto-generated method stub
return false;
}
#Override
public int hashCode()
{
// TODO Auto-generated method stub
return 0;
}
#Override
public Object executarConsultaPersonalizada(NomeMetodo nome,
Parametros parametros)
{
// TODO Auto-generated method stub
return null;
}
public boolean daoCompativel(Class<?> clazz)
{
return GrupoDeAcao.class.equals(clazz);
}
The class AbsDao is a generic class that have in your methods, save, update e etc.
And this class have the #Repository and #Transactional Anotations

Hibernate Interceptor Not Working

I have a simple HibernateInterceptor in which basically I want to set a few fields automatically. This interceptor (shown below) extends EmptyInterceptor:
public class EntityAuditInterceptor extends EmptyInterceptor {
/**
* The Serial Version UUID.
*/
private static final long serialVersionUID = 4636626262147801287L;
/* (non-Javadoc)
* #see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
*/
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
// doing stuff here
return false;
}
/* (non-Javadoc)
* #see org.hibernate.EmptyInterceptor#onSave(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
*/
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
// doing stuff here
return false;
}
}
I am wiring using a spring config file as follows:
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="hsqlDbDataSource"/>
<property name="packagesToScan">
<list>
<value>com.dreamteam.lms.**.*</value>
</list>
</property>
<!-- Adding Interceptor here -->
<property name="entityInterceptor">
<bean class="com.dreamteam.lms.interceptors.EntityAuditInterceptor"></bean>
</property>
<property name="hibernateProperties">
<props>
<!--<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>-->
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
</props>
</property>
</bean>
However, the Interceptor is never reached. Does anyone have any clue? I have also tried adding the following to the transaction manager bean definition as follows:
<property name="entityInterceptor">
<ref local="entityAuditInterceptor"/>
</property>
Ok, just for the record, I solved this problem which turned out to be a stupid mistake from my part.
When I implemented my interceptor that extends EmptyInterceptor I added the method 'onFlushDirty' and so on. So far so good. The problem was that on using my IDE to auto-import the used classes, I ended up importing java.reflect.Type instead of org.hibernate.type.Type by mistake. Hence, I was not really overriding the interceptor method!
I noticed that when I added the #Override interceptor to my method.
Another mystery solved ... :)
It looks like your Spring XML configuration is correct, so Hibernate should be calling your interceptor methods. However those methods appear to always return false which means that Hibernate will ignore any changes you make.
When you change a value you must return true. For example, this code iterates through all the properties and returns true if and only if a change is made:
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
boolean changed = false;
for (int i = 0; i < propertyNames.length; i++) {
if ("saveDate".equals(propertyNames[i])) {
currentState[i] = new Date();
changed = true;
}
}
return changed;
}

Resources