Is PersistenceAnnotationBeanPostProcessor of any use at all?

10,033

Solution 1

The PersistenceAnnotationBeanPostProcessor transparently activated by the <context:component-scan /> element. To be precise it's the <context:annotation-config /> element that activates the bean but this element in turn gets transparently activated by <context:component-scan />.

Solution 2

As Oliver Gierke mentioned, org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor is automatically loaded into App Context by Spring when using annotation based configuration. One of its duties is to search the proper entity EntityManagerFactory that would provide the EntityManager for you @PersistenceContext annotated properties.

If you have multiple EntityManagerFactory beans in you spring config/context and you have @PersistenceContext annotations without a unitName attribute (lets say you are using a framework that comes with such a bean, and you can't touch framework code), you may run into this exception: org.springframework.beans.factory.NoUniqueBeanDefinitionException.

I found this workaround in case you tun into this:

<bean id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
<property name="defaultPersistenceUnitName" value="entityManagerFactory"/>
</bean> 

This would override the default PersistenceAnnotationBeanPostProcessor loaded by Spring with a new one with defaultPersistenceUnitName.

Share:
10,033
Mingtao Sun
Author by

Mingtao Sun

Updated on June 23, 2022

Comments

  • Mingtao Sun
    Mingtao Sun almost 2 years

    According to its JavaDoc, PersistenceAnnotationBeanPostProcessor seems to be responsible for injecting the EntityManager with the annotation @PersistenceContext. It appears to imply without this bean declared in the Spring application context xml, the @PersistenceContext annotation won't work.

    However, based on my experiments, this is not the truth.

    Persistence.xml

    <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_1_0.xsd"
        version="1.0">
        <persistence-unit name="default" transaction-type="RESOURCE_LOCAL" />
    </persistence>
    

    Spring application context XML

    <context:component-scan base-package="com.test.dao" />
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="default"/>
        <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.DerbyDialect"/>
            </bean>
        </property>
    </bean>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver"/>
        <property name="url" value="jdbc:derby://localhost:1527/c:\derbydb\mydb"/>
        <property name="username" value="APP"/>
        <property name="password" value="APP"/>
    </bean>
    
    <tx:annotation-driven/>
    
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    
    <!-- 
        <bean id="persistenceAnnotation" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     -->
    

    UserDaoImpl

    @Repository("userDao")
    public class UserDaoImpl implements UserDao {
    
        @PersistenceContext
        protected EntityManager entityManager;
    
        @Transactional
        public void save(User user) {
                entityManager.persist(user);
        }
    }
    

    Whether I comment or uncomment the persistenceAnnotation bean, the result is the same. It doesn't hurt to leave the bean around, but what's the use of this bean?

    I am using Spring 3.0.5.

    Could someone provide a scenario where taking out this bean will result in failure?

    Also I am not fond of creating an empty persistence unit just to fool Spring. Luckily this problem has been addressed in Spring 3.1.0.