MemeStorm

Exploring the Spring Framework and Application Development

Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP)

Posted in All by Jon on the October 30th, 2006

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.

springjpa.zip

Technorati Tags:
,


Print This Post Print This Post

13 Responses to 'Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP)'

Subscribe to comments with RSS or TrackBack to 'Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP)'.


  1. on October 31st, 2006 at 4:40 pm

    […] MemeStorm » Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP) […]


  2. on November 13th, 2006 at 5:37 pm

    […] Java Persistence API (JPA), Spring and Eclipse Web Tools Platform (WTP) […]

  3. Eric Ma said,

    on November 21st, 2006 at 5:29 am

    Great example! Quick question - have you tried to deploy the app on WebLogic 9.2? I tried and it gives all kinds of errors (spring related). Packaging toplink_essentials_agent.jar in the .war does not help. Thanks,

  4. Filipe said,

    on January 25th, 2007 at 6:41 am

    Its a good thing to understand Spring.
    But Im getting some problem. I didnt can execute this in Eclipse and Tomcat inside.
    When Im using the war outside of Eclipse/Tomcat I got a error. It cannot find the MyDAOImpl.
    I putted the springapp.jar inside the project build path, but this didnt works.
    What more can I do??

  5. tech said,

    on January 25th, 2007 at 7:40 am

    See the build instructions in the zip. You need to build it with the full Spring 2.0 distribution available so that it can grab the necessary files to make the WAR (including spring.jar and the JPA, hsqldb jars etc.)

  6. Filipe Fumaux said,

    on January 26th, 2007 at 2:05 pm

    People, I made a conf in this project to build in Eclipse w/ Tomcat plugin and Oracle. I worked so hard to config this project. This thing happened because I dont know about Spring+JPA so much.
    So, Im changing this project adding my things. This project that Im doing it just a page that had a form to make a search in the DB.
    My question is just about the performace around this structure.
    Anybody knows about it??

  7. Terje said,

    on January 27th, 2007 at 5:07 pm

    Very nice excample. But I’m having problems running it. I’ve build the war file running build.xml in eclipse, and deployed it on my TomCat 5.5.20 using the Tomcat Web Application Manager. It deploys successfully, but when I’m trying to open the webapp, I just get, The requested resource (/springjpa/) is not available. So I’m kind of stuck….any ideas?

    thanx :)

  8. tech said,

    on January 29th, 2007 at 3:17 am

    It might not be /springjpa/. Please check the readme that accompanies the download. Also, Tomcat has a manager web-app that can tell you what is deployed where. Hope that helps.

  9. Terje said,

    on February 2nd, 2007 at 3:59 pm

    I’ve finally got the example up and working now, but when I’m trying to access adduserform.jsp, I get the following error:

    javax.servlet.ServletException: Neither Errors instance nor plain target object for bean name ‘user’ available as request attribute

    I’m not sure what causes this.

  10. Terje said,

    on February 16th, 2007 at 3:04 pm

    Using this pattern, how do I map everything else then JSP files. Like graphics (JPG, GIFS etc..) When a jsp page contains urls to jpg files in tags, I get the following type of messages from Tomcat:

    WARNING: No mapping for [/demotape/go/main/gfx/shadow_A_bottom.jpg] in DispatcherServlet with name ‘dispatch’
    16.feb.2007 23:55:42 org.springframework.web.servlet.DispatcherServlet noHandlerFound

    I’m kind of stuck on this, any help would be much apriciated…

  11. Nguyen said,

    on April 9th, 2007 at 10:02 am

    Thanks for the tutorial. Is it possible to give an example where you configure multiple data sources for different transaction managers with different DAO object?

  12. Rickou said,

    on June 11th, 2007 at 2:53 am

    Thanks for this tutorial.

    I succeded in deploying this application build with the ant script but not in Eclipse environnement …

    Note: the parameters of the JVM are the same for Tomcat 5.5

    Any idea ?

  13. Alan said,

    on April 8th, 2008 at 3:16 am

    Thank you, thank you, thank you! (Mind you, I haven’t tried it out yet…)

Leave a Reply