Announcement Announcement Module
Collapse
No announcement yet.
Help me mend Frankenstein's Monster (Spring + JPA) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help me mend Frankenstein's Monster (Spring + JPA)

    Hi Guys,

    All I wanted to do was write a Spring/JPA application that inserted a row into a table. How hard can this be?
    Right now the program creates the table but sadly won't populate it. (No errors).
    The code is as follows:
    Maven pom file
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>org.springframework.samples.spring</groupId>
    	<artifactId>spring-jpa-utility</artifactId>
    	<version>1.0.0.CI-SNAPSHOT</version>
    	<packaging>jar</packaging>
    	<name>Spring JPA Utility</name>
    	<url>http://www.springframework.org</url>
    	<description>
    		<![CDATA[This project is a minimal jar utility with Spring configuration for JPA usage.]]>
    	</description>
    	<properties>
    		<maven.test.failure.ignore>true</maven.test.failure.ignore>
    		<spring.framework.version>3.0.6.RELEASE</spring.framework.version>
    	</properties>
    	<dependencies>	
    		<dependency>
    			<groupId>org.hibernate</groupId>
    			<artifactId>hibernate-entitymanager</artifactId>
    			<version>3.6.0.Final</version>
    		</dependency>
    		<dependency>
    			<groupId>javax.validation</groupId>
    			<artifactId>validation-api</artifactId>
    			<version>1.0.0.GA</version>
    		</dependency>
    		<dependency>
    			<groupId>org.hibernate</groupId>
    			<artifactId>hibernate-validator</artifactId>
    			<version>4.1.0.Final</version>
    		</dependency>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.7</version>
    			<scope>test</scope>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-test</artifactId>
    			<version>${spring.framework.version}</version>
    			<scope>test</scope>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context-support</artifactId>
    			<version>${spring.framework.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-aop</artifactId>
    			<version>${spring.framework.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-orm</artifactId>
    			<version>${spring.framework.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>commons-dbcp</groupId>
    			<artifactId>commons-dbcp</artifactId>
    			<version>1.2.2</version>
    		</dependency>
    		<dependency>
    			<groupId>com.h2database</groupId>
    			<artifactId>h2</artifactId>
    			<version>1.3.156</version>
    		</dependency>
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>1.2.16</version>
    		</dependency>
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>5.1.24</version>
    		</dependency>
    	</dependencies>
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<configuration>
    					<source>1.5</source>
    					<target>1.5</target>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    	
    </project>
    The Springbean config file:
    Code:
    <?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"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    
    	<context:component-scan base-package="com.fdmgroup.TestSpringJPA" />
    	<context:annotation-config />
    	<bean id="transactionManager"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    	<bean id="emf"
    		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    
    		<property name="persistenceUnitName" value="compPu" />
    	</bean>
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.current_session_context_class">thread</prop>
    				<prop key="dialect">org.hibernate.dialect.HSQLDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    	</bean>
    	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    	<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
    		<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/test" />
    		<property name="username" value="test" />
    		<property name="password" value="test" />
    	</bean>
    	<tx:annotation-driven />
    </beans>
    The persistence.xml file under src/main/resources/META-INF
    Code:
    <?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_1_0.xsd"
        version="1.0">
        <persistence-unit name="compPu" >    
            <properties>
                <property name="hibernate.hbm2ddl.auto" value="create"/>
                <property name="hibernate.current_session_context_class" value="thread" />
                <property name="hibernate.archive.autodetection" value="class, hbm"/>
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
                <property name="hibernate.connection.password" value="test"/>
                <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="hibernate.connection.username" value="test"/>
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
                <property name="hibernate.c3p0.min_size" value="5"/>
                <property name="hibernate.c3p0.max_size" value="20"/>
                <property name="hibernate.c3p0.timeout" value="300"/>
                <property name="hibernate.c3p0.max_statements" value="50"/>
                <property name="hibernate.c3p0.idle_test_period" value="3000"/>
            </properties>
        </persistence-unit>
    </persistence>
    The DAO implementation
    Code:
    package com.fdmgroup.TestSpringJPA;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    @Repository("companyDAO")
    @Transactional
    public class JPACompanyDAO implements CompanyDAO {
    	@PersistenceContext
    	private EntityManager em;
    	@Transactional
    	public void addCompany(Company comp) {
    		em.persist(comp);
    		//em.getTransaction().commit();  // creates horrible error messages if uncommented
    		em.close();
    		
    	}
    
    }

    DAO Interface:
    Code:
    package com.fdmgroup.TestSpringJPA;
    
    public interface CompanyDAO {
    	
    	public void addCompany(Company comp);
    
    }

    Object to be persisted:

    Code:
    package com.fdmgroup.TestSpringJPA;
    
    import javax.persistence.Entity;
    import javax.persistence.Id;
    
    
    @Entity
    public class Company {
    	
    	
    	@Id
    	private int id;
    	private String compName;
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getCompName() {
    		return compName;
    	}
    	public void setCompName(String compName) {
    		this.compName = compName;
    	}
    	
    	
    
    }

    Driver App:

    Code:
    package com.fdmgroup.TestSpringJPA;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * Hello world!
     *
     */
    public class App 
    {
        public static void main( String[] args )
        {
            ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
            CompanyDAO cd = (CompanyDAO) ac.getBean("companyDAO");
            
            Company comp = new Company();
            comp.setId(1);
            comp.setCompName("Tilda Swinton");
            
            cd.addCompany(comp);
            
            
            
        }
    }

    I'm sure there are many problems with this code, as I've applied changes using the internet from all over the shop.

    Please can you help?

    regards,

    Kevin.

  • #2
    From what I gathered from a bit of googling is that you are

    1. mixing Hibernate beans and JPA beans, and not fully configuring the JPA beans
    2. using a JPA EntityManager, and not a Hibernate session factory, in your DAO.

    So, you can basically get rid of the Hibernate-specific bean definitions in the spring.xml file and just complete the JPA bean configuration.

    Try the following Spring bean config file, substituting in the correct values where I have placed "...":

    Code:
    <?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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    
    	<context:component-scan base-package="..." />
    	<context:annotation-config />
    
    	<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/..." />
    		<property name="username" value="..." />
    		<property name="password" value="..." />
    	</bean>
    
    	<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="persistenceUnitName" value="..." />
    		<property name="dataSource" ref="dataSource" />
    		<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    		</property>
    		<property name="jpaProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    			</props>
    		</property>		
    	</bean>
    
    	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="emf" />
    	</bean>
    
    	<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
    
    </beans>
    You may want to declare your Company class in the persistence.xml file, as well.

    Once I used the above with your existing code, things just worked as verified by using MySQL's admin tool to query the company table.

    Oh, finally, the general consensus is that you should introduce a "service" layer, call the DAO from there, and put the @Transactional declarations in the service layer. And, personally, instead of writing an App class with a main() method to essentially do testing, I would immediately create a unit test class and do the test there. Avoid at all costs creating little apps [i.e., those with a "main()" method] to do any testing.

    [Added in editing]
    And finally, finally! I think it's not advised to use "org.springframework.jdbc.datasource.DriverManager DataSource". You seem to indicate in your persistence.xml file that you want to use C3P0, so you might redefine your dataSource:

    Code:
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"  >
    	<property name="jdbcUrl" value="${jdbc.url}" />
    	<property name="driverClass" value="${jdbc.driverClassName}" />
    	<property name="user" value="${jdbc.username}" />
    	<property name="password" value="${jdbc.password}" />
    </bean>
    Last edited by pfurbacher; Apr 11th, 2013, 11:39 AM.

    Comment

    Working...
    X