Testing Java Persistence API (JPA) Entities Outside the Container
When I wrote about the Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP) I neglected to show how easy it was to test our JPA entities.
Traditionally, testing EJBs outside of a container was an absolute pain. Testing JPA is embarrassingly easy, especially with Spring doing all the heavy lifting. You’ll have no excuse to write your integration tests now..
Our goal
Our goal here is to test or DAO class, MyDAO, shown here. This can be used as the basis of larger integration tests for example. Here are some of the issues in setting up a test, which we’ll neatly sidestep later:
- We need to set up the entity manager, hopefully just once as this is time consuming.
- We need to handle the automatic dependency injection. Remember that this DAO can run on a server, where it expects the entity manager to be automatically injected.
- We need some kind of transaction management. Ideally we don’t want to start and commit transactions in every test method. DRY!
- A popular way of testing code that interacts with databases these days is to start each test with a transaction, and then after running the test, roll back the transaction so that any database changes aren’t actually committed. This leaves your database in an orderly state.
- Ideally we’d like access to JDBC too - just to check our JPA stuff is doing its thang.
- We may need to handle class instrumentation when using JPA
How to do it
Well, I’m going to show you some code that does all of the above. You’ll be shocked at how little I have to do:
import org.springframework.test.jpa.AbstractJpaTests;
public class MyDAOTests extends AbstractJpaTests {
MyDAO myDAO;
@Override
protected String[] getConfigLocations() {
return new String[] {
"/com/memestorm/service/jpa/applicationContext.xml",
"/com/memestorm/service/jpa/applicationContext-jpa.xml"
};
}
public void testInsertUser() {
Collection users = getMemeService().getUsers();
int found = users.size();
User u = new User("test", "test");
getMemeService().addUser(u);
users = getMemeService().getUsers();
assertEquals(found + 1, users.size());
}
// More tests... then
public MyDAO getMemeService() {
return myDAO;
}
}
I’m sorry, did you blink? Go read that again. Isn’t that neat? Let’s look at what’s happening:
- Obviously the
getConfigLocations()method points to our application context configuration files (I’m using the same ones as in the previous blog entry). Spring uses this to establish the entity manager, database connections etc. It does this once, and all the tests methods use the results. - Spring automatically injected the dependencies. Did you see that
myDAOvariable and its setter? Spring managed that itself. - Spring automatically starts a transaction for every test method and rolls it back afterwards.
- Spring silently handles all class instrumentation.
Now you have no excuses for writing your own tests. You are positively coddled by AbstractJpaTests.
Adding a few features
AbstractJpaTests provides a lot of additional functionality.
JDBC
Sometimes you want to incorporate some JDBC too. Here’s a method that does so:
public void testInsertUserSQL() {
Collection users = getMemeService().getUsers();
int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM USER");
assertEquals(users.size(), count);
}
Easy huh? The jdbcTemplate is set up for you in one of the superclasses.
Transactions
You don’t have to wait until the method ends to end the transaction. You can optionally call the method endTransaction() if you like. By default, this will force the rollback of the transaction—remember that’s what typically happens automatically for you at the end of each test method.
If you want the transaction to actually commit for a particular test method, then call the setComplete() method. This sets a flag, read in the endTransaction() method, to tell the test harness to commit instead of rollback. More complex operations can be carried out too, for example you can end a transaction in a test method, and in the same method begin a new one by calling startNewTransaction(). Check out Spring’s AbstractTransactionalSpringContextTests for all of this support.
Entity Manager
You can also get access to the entity manager. Here’s an example that uses some of JPA’s Query interface:
public void testNamedParameter() {
User us = new User("test","last");
getMemeService().storeUser(us);
Query q = this.sharedEntityManager.createQuery(
"select u from User u where u.firstName = :name");
q.setParameter("name", "test");
User u = (User) q.getSingleResult();
assertEquals(u.getFirstName(), "test");
}
As you can see, the exposed sharedEntityManager is the entity manager attached to the current transaction.
Caveats
Say you have a User class that’s in a ManyToOne unidirectional relationship with a Building class, like this:
@Entity
public class User {
/* Unidirectional */
@ManyToOne
@JoinColumn(name="bldng_id")
Building building;
// ..
}
Imagine we write a test case, like this:
public void testBuilding() {
User u = new User("test","test");
Building b = new Building();
b.setName("BuildingA");
u.setBuilding(b);
getMemeService().addUser(u);
**//getMemeService().addBuilding(b);**
}
Here we’ve made a mistake and didn’t persist the building object (it’s required - it’s not cascaded after all). What will happen when you run this test?
Well, the green flag will be raised high, unfortunately. Say we changed the test like so:
public void testBuilding() {
User u = new User("test","test");
Building b = new Building();
b.setName("BuildingA");
u.setBuilding(b);
getMemeService().addUser(u);
Collection usersAfter = getMemeService().getUsers();
}
If you run this test, you’ll get an exception
java.lang.IllegalStateException: During synchronization
a new object was found through a relationship that was
not marked cascade PERSIST.
In other words, the getUsers() method, which simply does em.createQuery("SELECT user from User user").getResultList(), results in the persistence context realizing that there is indeed an object that should have been persisted.
My point is this: I’ve added the final test line there for no good reason, but it’s caught a bug in my persistence logic. That’s a bit ugly - I wish there was some way in which I could force the O/R tool to do some kind of “spot consistency check” to help me out. Hopefully if we have enough tests in our service layer going through to the DAO layer, it’ll catch these types of things. Perhaps Andy over at the excellent Disco Blog will be kind enough to point the way one day ![]()
Print This Post
Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP)
It’s time to add some persistence to our talks. I spent a good two hours trying to get Spring, JPA and Eclipse to play along. Here’s what I eventually did…So our goal is to create a project that I can run from within Eclipse, or deploy to something like Tomcat or an application server. It uses HSQLDB, though you can obviously change database, and Toplink Essentials (though you can obviously change JPA provider too). I use Tomcat 5.5.20 here. Oh, and Spring 2.0. All of the necessary software libraries (besides Tomcat) can be found bundled in the full Spring 2.0 distribution. I don’t use all of Spring’s JPA utilities either - I tried to stick to generic JPA stuff.
Our JPA Code
The only tricky part is setting up the application context for JPA’s entity manager factory. After that it’s plain sailing, writing nice JPA code. Here’s an example of one of the beans in our model:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
String firstName;
String lastName;
@OneToOne
@JoinColumn(name="pwd_id")
Password password;
@ManyToOne
@JoinColumn(name="bldng_id")
Building building;
@OneToOne(mappedBy="owner")
Cup cup;
// omitted getters and setters
}
It’s a POJO, appropriately annotated. In this case we have some extra OneToOne (unidirectional), ManyToOne (unidirectional) and OneToOne(bidirectional) relationships, but feel free to omit them. This is pure POJO and JPA - there is no Spring in here at all.
That’s the kind of code we want to write for our domain model, so what about our DAO code? Here’s our full DAO:
@Transactional
public class MyDAOImpl implements MyDAO {
private EntityManager em;
// Spring will inject this:
@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}
public Collection getUsers() {
return em.createQuery("SELECT user from User user").
getResultList();
}
public User loadUser(int id) {
return em.find(User.class, id);
}
public void addUser(User user) {
em.persist(user);
}
public Cup getCup(int id) {
return em.find(Cup.class, id);
}
}
This is pretty straightforward. The only Spring dependency we have here is the @Transactional, and that’s because I wanted Spring to make all the methods transactional and avoid writing blobs of repeated code. Notice the standard @PersistenceContext annotation. Spring will magically fill this in for us - it acts like a JPA container.
I like this code. It’s all neat, with minimal dependencies. Let’s look at how to wire it up to work with Spring.
Spring’s Application Context
I’ve created an applicationContext-jpa.xml configuration file for all the JPA stuff. It’s all pretty obvious once explained, I think…Here are all the bits with commentary:
First we set up a nice little property configurer, so you can just modify jdbc.properties to change the database:
<bean id="propertyConfigurer" class="org.....PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/jdbc.properties"/>
</bean>
Now a simple datasource:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
Now for the meaty bit:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="MySpring"/>
<property name="dataSource" ref="dataSource"/>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<!-- I'm not sure this is really necessary.. -->
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
<property name="databasePlatform"
value="oracle.toplink.essentials.platform.database.HSQLPlatform"/>
<property name="generateDdl" value="true"/>
<property name="showSql" value="true" />
</bean>
</property>
</bean>
Now the important bit is the type of Spring entity manager factory you choose, and the weaver. Many JPA implementations (not all) require a runtime weaver of some kind. I had real trouble getting things to work with the SimpleLoadTimeWeaver in Eclipse. I suspect class loading errors were causing the problem. I ended up with the InstrumentationLoadTimeWeaver which requires that you start your Java VM with an additional argument:
-javaagent:/Java/workspace2/spring/dist/weavers/spring-agent.jar
To do this in Eclipse, hit “Run”, then “Run…” - select your server (for example, “Tomcat 5.5 Server”), hit the “Arguments” tab and insert the above in the “VM Arguments” box.
Some of the other weavers require me to modify Tomcat (by adding a context.xml file for example) to make Tomcat use Spring’s weaver - but I could not figure out how to do this with WTP - WTP provides no way for me to set this.
Moving on:
<!-- A simple transaction manager for our (single) EntityManagerFactory. -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>
Here we create a simple transaction manager, and tell Spring we want to use its declarative @Transaction management.
This makes Spring perform the magic @PersistenceContext/@PersitenceUnit injection:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
Finally, we can declare our DAO:
<bean id="service" class="com.memestorm.service.jpa.MyDAOImpl" />
Note that we don’t specify the entity manager as a dependency. The bean post processor above will sort that out for us.
That’s it, we’re done! In the end, there wasn’t too much to it except for the wrangling with the various weavers and entity managers. Ben Hale provides a similar writeup though I got the same org.springframework.dao.InvalidDataAccessApiUsageException exceptions as some of his readers.
Download
The full source for the application is here. As usual, it assumes that you have the full Spring distribution unpacked in a sibling directory. Run the libraries Ant task to transfer the dependencies, and the server.sh in the db directory to start the database. I’ve run this within Eclipse (3.2.1) WTP (1.5.1) successfully, and deployed as a WAR to Tomcat 5.5.20.
Technorati Tags:
Spring Framework,
JPA
Print This Post
Session-scoped Beans in Spring 2.0
Spring 2.0 introduces a new way of scoping beans. We’ve spoken about singleton scoped beans in the past and there are factory beans too. Now there are session, request and other types of bean scopes. As you might imagine, a Spring bean scoped to the sessions means that it lives as long as the session. This means that if you ask Spring’s IoC container for a bean that is session-scoped, it will instantiate it once only for that particular user’s session—different users in different sessions will get their own bean instances. It gets even cooler if you set this bean as a dependency for another bean that is a singleton. It still works, but in this case Spring injects a smart proxy to handle the dynamic bean swapping (the container bean will get a different dependent bean depending on the session). All of this magic is dead simple to implement and use.
How to do it
Let’s look at how to create a simple session-scoped bean that can be retrieved from the context. If you are using a DispatcherServlet (which you will be if you are using Spring’s MVC) then all you need to do is tag the bean as session-scoped in your application context configuration file. For example:
<bean id="mybean" class="com.memestorm.ex.MyBean"
scope=”session”/>
Not much to do…as you’ll see, the only difference is the session attribute. If you aren’t using the DispatcherServlet then you’ll need to add a (small) bit of extra configuration to web.xml:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
You need to do this because of the mechanics of how this is implemented, which we’ll look at later. For now remember that if you’re already using Spring’s MVC, you don’t need to do anything. The bean, MyBean is nothing special—here’s the one we use:
public class MyBean {
public MyBean() {
System.err.println("In Constructor!!!");
}
}
So now that we’ve defined our bean in our context, how do we use it? Well, just like you’d use any other bean really! Here’s an example of a controller grabbing the bean from our application context:
// retrieve context
ApplicationContext ac = org.springframework.web.context.support.
WebApplicationContextUtils.getRequiredWebApplicationContext(
request.getSession().getServletContext());
// grab bean
MyBean mb = (MyBean) ac.getBean("mybean");
This is what you’d do anyway. The key isn’t that you have change the way you program - but it’s the way Spring manages the creation of the bean.
What happens?
The bean (MyBean) won’t be created only once (a singleton) for all users—rather it will be created once for each user session. The magic is that it’s effectively tied to the user’s session (and created lazily as a result). Here’s a concrete use case used in the Spring documentation: User Preferences. If your user is logged on and you retrieve a session-scoped bean for the first time, it will be created. While the user is logged on (he has a session) that bean will remain effectively tied to the session so that if you access the bean again (from the context), it will simply retrieve it and not create it again.
You can test this with the supplied example. The index handler just tells me if the session is new (if it is, and you access the bean, you should expect a new instance to be created). The access handler actually tries to retrieve the bean from the context. You’d expect this to create the bean if the session is new, or simply just retrieve it if it’s not. The invalidate handler invalidates the session. Download the example and play - check the console to see the constructor message and when it appears.
More Advanced Work
Let’s look at the situation with dependencies. For example, imagine our session-scoped bean has a dependency on some singleton:
<bean id="myotherbean" class="com.memestorm.ex.MyOtherBean" />
<bean id="mybean" class="com.memestorm.ex.MyBean" scope="session">
<property name="mob" ref="myotherbean" />
</bean>
What happens now? Well, myotherbean will be created once with the context, and the same instance will be injected into each mybean instance that is created as each user creates a session. Neat huh? But I guess you’d expect that behaviour.
Even More Advanced Work
Let’s flip the injection described in the previous scenario. Imagine you have a bean that has a session-scoped bean as a dependency:
<bean id="mybean" class="com.memestorm.ex.MyBean" scope="session">
<property name="mob" ref="myotherbean" />
<aop:scoped-proxy/>
</bean>
<bean id=”yetanotherbean” class=”com.memestorm.ex.YetAnotherBean”>
<property name=”mybean” ref=”mybean” />
</bean>
You’ll notice I had to do one surprising thing—it’s that magic AOP proxy incantation. Essentially the problem is this: if mybean is only created when accessed from a session, and multiple times for each different session, how do we know what to inject into yetanotherbean because yetanotherbean is a simple singleton created when the Spring context is created?
The answer is of course: it doesn’t and cannot know. So what we have to do is stuff in a proxy that behaves like the object (in fact it goes and grabs the object from the user’s session when you access it). Spring does all the heavy lifting for you in this case - all you need to do is add the scoped-proxy tag. This is pretty neat magic. I’ve included a download to a more advanced application that uses this approach too. Note that to do this proxying Spring needs cglib in the classpath.
Downloads
- Simple: scopexample.zip
- AOP dynamic dependency version: ascopexample.zip
Print This Post
Lazy bean instantiation in Spring 2.0
Spring 2.0 introduces a new way of instantiating beans defined in a
bean factory—lazily. Generally all singleton beans are
instantiated as one of the last things that a bean factory does. You
can now change this behaviour slightly and ensure that a bean factory
doesn’t instantiate your bean at all - until such time as it’s
requested for example.
How to do it
Simply use the new lazy-init attribute in your bean definition. For example:
<bean id="turtle" class="com.memestorm.FooT"
lazy-init=”true” />
<bean id=”fox” class=”com.memestorm.FooF”
lazy-init=”false” />
Here turtle is defined to instantiate lazily, while fox will do so eagerly. In fact, we don’t need the lazy-init="false" attribute on fox at all - by default things are not lazy.
What happens?
Well, if these beans were defined in your application context then the fox bean will be created as usual (eagerly, as a singleton), but the turtle won’t be. That’s almost all there is to it. Of course, if your Java code tries to grab the bean from the context it will be instantiated at that time:
FooF = (FooF) context.getBean("fox");
There is a caveat. If turtle was defined as dependency of fox, then of course the context will ensure that turtle is created eagerly too. It’s the only way to satisfy the constraint after all. So for example, here both beans will be created eagerly even though one is marked as lazy:
<bean id="not-quite-turtle" class="com.memestorm.FooT"
lazy-init=”true” />
<bean id=”fox” class=”com.memestorm.FooF”
depends-on=”turtle” />
A possible use
I found a possible use in the petclinic application distributed with Spring. Here it is in a nutshell. Say you have two beans, in this case implementing specialized functionality:
<bean id="hsqlClinic" class="org.springframework.....HsqlJdbcClinic"
lazy-init="true">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mysqlClinic" class="org.springframework.....MySQLJdbcClinic"
lazy-init="true">
<property name="dataSource" ref="dataSource"/>
</bean>
Now say one of these classes will be used somewhere, say as the target of an transaction intercepter:
<bean id="clinic" class="org....TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="${petclinic.jdbcImplBeanName}"/>
</bean>
Now it should be clear to you. If, in my properties file, I set petclinic.jdbcImplBeanName=hsqlClinic, then the hsqlClinic bean will be used. Moreover, the mysqlClinic bean won’t even be instantiated. This nicely externalizes the configuration. To switch implementations, merely change the property to mysqlClinic.
How does it work?
You don’t have to know this, but here’s how the magic happens. The essential difference is in the preInstantiateSingletons() method in DefaultListableBeanFactory. This is the magic method that pre-instantiates all singletons defined in the bean factory. All that’s changed here, is that it ignores the bean if the lazy-init is set to true:
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
if (!cacheContainsSingleton(beanName) && containsBeanDefinition(beanName)) {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
….do instantiation work and put result in cache….
}
}
}
ioc lazy
Print This Post
Next Page »