Spring JPA / Hibernate EmptyInterceptor does not inject Entitymanager / Spring beans

Experts / GURU / Friends

We are working with Spring 3.2, JPA 2, Hibernate 4.2 combo and are facing this strange null pointer error when trying to inject any Spring annotated beans into the EmtyInterceptor implemented as shown below. We tried to annotate this bean as well as the Spring bean, but no luck.

Any help with this puzzle is greatly appreciated here.

import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.transaction.annotation.Transactional;
...

@Named
@Transactional
public class AuditEmptyInterceptor extends EmptyInterceptor {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    // Didnt inject - Null
    @PersistenceContext
    private EntityManager entityManager;

    // Didnt inject - Null
    //@PersistenceUnit
    //private EntityManagerFactory entityManagerFactory;

    // Didnt inject - Null
    //@Inject
    //private AuditHelper auditHelper;

    @Override
    public boolean onSave(Object entity, Serializable id, Object[] currentState,
            String[] propertyNames, Type[] types) {

        System.out.println("**********inside OnSave() in Audit Empty Interceptor******************");
        if(entity instanceof xxAuditInterface || entity instanceof xxxCompBranchInterface){
            for (int i = 0; i < propertyNames.length; i++) {
         ...
         ...
         // Null entityManager - NPE here
        javax.persistence.Query query = entityManager.createQuery("Select c From CompanyDO c Where c.companyName =:companyName");
        query.setParameter("companyName", xxx);
        CompanyMasterDO companyMasterDO = (CompanyMasterDO) query.getSingleResult();
         ...
         ...
          }
         }
        }

 }

      

Throughout the app, injection works like a charm without any problem. Here is our applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" 
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">


<context:annotation-config></context:annotation-config> 

<context:component-scan base-package="com" />

<context:property-placeholder location="classpath*:hibernate.properties" />
<tx:annotation-driven />

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com"/>
 </bean>

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/rcent_rel_2"
    p:username="root" p:password="root" />

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="persistenceXmlLocation" value="classpath*:META-INF/spring-persistence.xml" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    p:entityManagerFactory-ref="entityManagerFactory" />

<bean id="jpaAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
    p:database="MYSQL" 
    p:showSql="false" 
    p:databasePlatform="org.hibernate.dialect.MySQL5Dialect"/>

<\beans>

      

And our spring-persistence.xml is below. Note that I've added the Emptyinceptor property here.

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="xxx" transaction-type="RESOURCE_LOCAL">
    <class>com.xxx</class>
         ...
         ...
    <properties>
           <property name="hibernate.ejb.interceptor"
                       value="com.company.demo.audit.AuditEmptyInterceptor" />           
    </properties>
    </persistence-unit>
</persistence>

      

Let me know your valuable thoughts / advice on this. Thanks again for your time to read this post.

Also I read the post Implementing JPA Entity Manager in Hibernate EmptyInterceptor . But it looks like they are manually trying to find a bean named for permission and I feel like there might be some other way.

+2


source to share


1 answer


AuditEmptyInterceptor

is not a Spring managed bean, it is instantiated by Hibernate so you cannot inject dependencies into it.

A static delegate can be used instead:

public class StaticDelegateInterceptor extends EmptyInterceptor {

    private static Interceptor interceptor; 

    public static void setInterceptor(Interceptor interceptor) {
        StaticDelegate.interceptor = interceptor;
    }

    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
      return StaticDelegate.interceptor.onSave(entity, id, state, propertyNames, types);
    }
    ...
}

      

Register StaticDelegateInterceptor on persistence.xml

<persistence>
    <persistence-unit name="xxx" transaction-type="RESOURCE_LOCAL">
       <class>com.xxx</class>
       ...
       ...
       <properties>
          <property name="hibernate.ejb.interceptor"
                   value="com.company.demo.audit.StaticDelegateInterceptor" />           
       </properties>
   </persistence-unit>
</persistence>

      



Change your current AuditEmptyInterceptor so that it registers with the StaticDelegateInterceptor:

@Named
@Transactional
public class AuditEmptyInterceptor extends EmptyInterceptor {  

     @PostConstruct
     public void init() {
          StaticDelagateInterceptor.setInterceptor(this);
     }
     ...
}

      

And finally, make sure your entityManagerFactory

bean depends on yours AuditEmptyInterceptor

by setting the dependency attribute:

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter"
depends-on="auditEmptyInterceptor" >
...
</bean>

      

+6


source







All Articles