How to inject @PersistenceContext in DAO generated by Hibernate3-maven-plugin

1.6k views Asked by At

I wanna create a Java Application based on Hibernate-3 and Spring Framework. To get the process easy I found hibernate3-maven-plugin that is able to perform reverse-engineering of the existing database.
Here there's example of POM:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>hibernate3-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <components>
            <component>
                <name>hbm2java</name>
                <outputDirectory>src/main/java</outputDirectory>
                <implementation>jdbcconfiguration</implementation>
            </component>
            <component>
                <name>hbm2dao</name>
                <outputDirectory>src/main/java</outputDirectory>
                <implementation>jdbcconfiguration</implementation>
            </component>
        </components>
        <componentProperties>
            <revengfile>/src/main/resources/model.reveng.xml</revengfile>
            <propertyfile>/src/main/resources/hibernate.properties</propertyfile>
            <jdk5>true</jdk5>
            <ejb3>true</ejb3>
        </componentProperties>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.18</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.1_3</version>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>hbm2java</goal>
                <goal>hbm2dao</goal>
            </goals>
        </execution>
    </executions>
</plugin>  

Then I set up the context of Spring:

<?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
            <property name="persistenceUnitName" value="gomer" />
        </bean>

        <bean id="entityManager" factory-bean="entityManagerFactory" factory-method="createEntityManager"/>

        <bean id="user" class="ru.tomtrix.first.db.UserHome">
            <property name="entityManager" ref="entityManager"/>
        </bean>
    </beans>

It perfectly generates an Entity file and a DAO file except the following. In DAO file there's a EntityManager:

@Stateless
public class UserHome {

    private static final Log log = LogFactory.getLog(UserHome.class);

    @PersistenceContext private EntityManager entityManager;  

... and this field hasn't got a setter! Eventually Spring throws the exception:

Invalid property 'entityManager' of bean class [ru.tomtrix.first.db.UserHome]: Bean property 'entityManager' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

Of course it's not a good practice to write the setter manually. I think there is a way to inject a manager properly. So how to do it without rewriting the generated file?

Corresponding information:
1) I'd like to create a stand alone application (and possibly run it in an Application Server like Tomcat)
2) model.reveng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering SYSTEM "http://www.hibernate.org/dtd/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
    <table-filter match-name=".*" package="ru.tomtrix.first.db"/>
</hibernate-reverse-engineering>  

3) persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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">

    <persistence-unit name="gomer" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>User</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="1234"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/users"/>
        </properties>
    </persistence-unit>
</persistence>
1

There are 1 answers

3
M. Deinum On BEST ANSWER

The problem is you are missing a part of the configuration. You need to tell Spring that you want to (also) use annotations for configuration. For this add the <context:annotation-config /> to your configuration and remove the setting of the entityManager

Next to that remove the calling of the factory method spring will handle all that for you.

Added tip use the version-less schemas insead of

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="gomer" />
    </bean>

    <bean id="user" class="ru.tomtrix.first.db.UserHome" />

</beans>

Your code might be problematic when you deploy it to a fullblown app server and you might run into issues with Spring and the EJB container competing over control of the beans. The hibernate plugin generates @Stateless session beans which in general will be picked up by the app. server (depending on which one you use).