JPA 2.0 and Spring 3.0 with Maven
I’m currently updating WicketCool to use Spring 3.0, JPA2.0 and latest Wicket. Here is a short summary of my research, a quick tutorial showing how to jump into Spring3.0 + JPA2.0 development using Maven.
1. Dependencies
a) Spring
To use 3.0 release of the Spring framework you can’t no longer add one dependency as you used to do it
<dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> </dependency>
This will no longer work. Spring framework is divided into 20 modules:
If you create web appliactions, you will probably need modules listed below:
- all from Core Container: Beans, Core, Context and Expression Language
- AOP
- from Data Access/Integration: Transactions, ORM
- from Web: Web (even if you don’t use SpringMVC, you still might consider OpenEntityManagerInViewFilter which is inside Web module
- Test
Thus set of dependencies that you need to include in your pom.xml are:
<properties> <spring.version>3.0.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> </dependecies>
b) JPA 2.0
Now that we have Spring dependencies sorted out, we can look at the JPA2.0. We must remember that JPA itself is only standard, thus when setting dependencies we are really choosing the provider. I could go with Hibernate or EclipseLink. Hibernate is still in beta state and EclispeLink is a reference implementation of the standard, so I thought that EclipseLink is a good way to go. However after recent discoveries (which took me quite some to figure out by the way), I thought I will stick with the Hibernate’s beta.
What is new in Hibernate’s recent release is that you no longer need to define dependencies to core, annotations, commons-annotations ect. It is now only one, single dependency. Second dependency is the API of the standard.
<dependencies> <dependency> <groupId>org.hibernate.java-persistence</groupId> <artifactId>jpa-api</artifactId> <version>2.0-cr-1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.5.0-Beta-2</version> </dependency> </dependencies>
You might also need to add JBoss repository:
<repositories> <repository> <id>JBoss Repo</id> <url>http://repository.jboss.com/maven2</url> </repository> </repositories>
2. Configuration
The simples application context configuration file can look like this:
<?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:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- holding properties for database connectivity /--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- enabling annotation driven configuration /--> <context:annotation-config/> <context:component-scan base-package="wcpackage"/> <tx:annotation-driven transaction-manager="transactionManager"/> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"/> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"/> <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="persistenceUnitName" value="wctemplatePU"></property> </bean> <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:database="${jpa.database}" p:showSql="${jpa.showSql}"/> </beans>
Given that wcpackage is a root package for component scan and wctemplatePU is name of the persistent unit.
Now all we need to do is to define persistence unit in META-INF/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"> <persistence-unit name="wctemplatePU" transaction-type="RESOURCE_LOCAL"> <properties> <property name="hibernate.hbm2ddl.auto" value="validate" /> </properties> </persistence-unit> </persistence>
And that is basically it. You have Spring configuration and now can use EntityManager in your services classes.
@Repository(value = "userDAO") public class UserDefaultDAO implements UserDAO { @PersistenceContext private EntityManager entityManager;
Injected EntityManager will be with transaction-scoped persistence context, resource_local transaction type (meaning transactions used from database not JTA). Hope everything is comprehensive. If you have any questions, please let me know.
See also:
Although it worked frpn Spring < 3.0, it has never been a good idea to use "spring”. 🙂
True. And also recently I realized, that there is dependency spring-full. I wonder if it still works 😉 I might try it just to see what happens
Spring 3.0 is broken in this area: http://jira.springframework.org/browse/SPR-6408.
AFAIK 3.1 will support JPA 2.0 fully.
Will it be solved by providing second support for JPA2 only or will Spring stick with one provider and will update those methods when thinks that JPA1.0 is obsolete?
Update: It will get into the 3.0.1 release: http://jira.springframework.org/browse/SPR-6408
Yep, I’ve seen JIRA yesterday as well 🙂 Once again thx for the info
supports spring 3.0 all jpa 2.0?
i’m trying to create a CriteriaQuery and this is the result:
$Proxy146 cannot be cast to javax.persistence.TypedQuery
on this line:
TypedQuery tq = getEntityManager().createQuery(query);
where is the problem? thanks
daniel: sorry for not replying, shouldn;t yuor code look like this:
TypedQuery tq = getEntityManager().createQuery(query, SomeEntityClass.class);
this should work,if you dont provide enitty class, you get normal Query, otherwise TypedQuery
OK, I just see Ke CAI’s message and I agree that is a Spring problem, because I tried with
TypedQuery tq = getEntityManager().createQuery(query, SomeEntityClass.class);
too and the result was the same. I will try to update my Spring dependencies and I will write you the result.
Thx for de info 🙂
We have used Spring3.0 testing framework with JPA and Hibernate3.
After successful integration of all these, we are able to perform CRUD operations on entities from UI.
When we tried creating test cases for DAO, we stuck with a problem of NOT Saving/Updating the data in DB except successful retreival.
Please help, if you have some solution.
I would really need to see some code if you want my help.
Vivek Andan and Daniel: I will try look into it as soon as possible. Will let you know with the research.
Thanks for the reference material. I was looking for some XSD URLs and your site was at the top.
I have the same problem:
java.lang.ClassCastException: $Proxy50 cannot be cast to javax.persistence.TypedQuery
at $Proxy38.createQuery(Unknown Source)
show me your code that throws exception
@Repository
public class ShopDaoImpl extends GenericDaoJpaImpl implements
ShopDao {
@PersistenceContext
transient EntityManager entityManager;
@Override
public Shop findByCrieria() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery c = cb.createQuery(Shop.class);
Root shop = c.from(Shop.class);
c.select(shop).where(cb.equal(shop.get(“name”), “petstore”));
TypedQuery q = entityManager.createQuery(c);
return q.getSingleResult();
}
}
Hi
first of all, does this code really compiles? Shouldn’t it be:
TypedQuery<Shop> q = entityManager.createQuery(c);
return q.getSingleResult();
?
I’ve created a method to yours and it’s working here:
public User findByLogin(String login) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery c = cb.createQuery(User.class);
Root user = c.from(User.class);
c.select(user).where(cb.equal(user.get(“login”), login));
TypedQuery q = entityManager.createQuery(c);
return q.getSingleResult();
}
and test:
@Test
public void shouldPersistUserInDataBase() throws Exception {
// given
assertEquals(1, userDAO.size());
User user = new User(“login”, “password”);
// when
userDAO.persist(user);
// then
assertEquals(2, userDAO.size());
User result = userDAO.findByLogin(“login”);
assertEquals(“login”, result.getLogin());
assertEquals(“password”, result.getPassword());
}
passes.
I will soon release WicketCool 0.7 where you will be able to see it in action.
If you have any other questions, let me know. You know my email address right?
I tried your code, but it still does not work.
I also asked this question in stackoverflow, some guys think this is a bug.
http://stackoverflow.com/questions/2101500/spring-3-0-orm-with-jpa-2-0-classcastexception/2102328#2102328
I created an issue in Spring JIRA. Hope this problem can be sloved soon.
which spring version do you use?
I recreated your code as close possible as I could, and it still works.
Is it a maven project? Can I see you pom?
By the way: Sydney right? You are lucky to have a summer now. Freaking freezing out here right now 🙂
You bet, very hot. I miss snow so much.
My project is maven project,
because of :http://jira.springframework.org/browse/SPR-6408
I use Spring, 3.0.1.BUILD-SNAPSHOT, Hibernate 3.5.0-Beta-3 .
I user Spring 3.0.0 and 3.5.0-Beta2.
I will update my dependencies tomorrow (as I go to bed right now) and tell you if anything changed. Ok?
Thanks, and have a sweet dream:)
[Spring-JIRA] Resolved: (SPR-6733) Spring 3.0 ORM with JPA 2.0 TypedQuery ClassCastException
They fixed this bug:)
ok, so it was hibernate3.5-beta3 problem (i’m still on beta2). Thx for the info.
Thanks for posting, the world needs more like this 🙂
I am trying to build/define a project and I am new to Maven. I wanted to develop web application on tomcat using Spring 3.0.3 , JPA and using Maven. I tried your article but I lost in middle as it doesn’t tell you steps from start i.e. step starting from maven to create project and then to configure it with JPA etc… Is it possible for you to write a article or give me guidance to write about project, may be with user login getting password using JPA from database. Actually I wanted to define good project structure using MAVEN.