Put together Struts2, JPA, Hibernate and Spring

This weekend I played a bit with Struts2. Obviously my first thought was to put together “fellowship of the ring” ie Struts, Spring and Hibernate. Now, we have two ways for integrating Hibernate and I’ve chosen the Java Persistence Architecture approach, because is the latest trend in terms of persistence in the J2EE landscape.

Create your domain model

For the sake of simplicity I’ll take  a simple example that contains Books and Authors. A book has one or more authors while one author wrote one or more books. This looks like a many to many relationship and we want to be able to get, from one shoot, the book and its authors and for an author his entire list of books.

Book.java

package org.bserban.shs.model;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "book")
public class Book {
    @Id
    @GeneratedValue
    private Integer id;
    private String title;
    private String publisher;
    private String keywords;
    private String ISBN13;
    private String ISBN10;
    @ManyToMany(fetch = FetchType.EAGER)
    private List<Author> authors;
........................................

Author. java

package org.bserban.shs.model;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "author")
public class Author {
    @Id
    @GeneratedValue
    private Integer id;
    private String firstName;
    private String lastName;
    private String blog;
    @ManyToMany(mappedBy="authors",fetch = FetchType.EAGER)
    private List<Book> books;
.......................................

As you see in the code snippets above, the many to many relationship was marked with @ManyToMany annotation. We specified that the many to many relationship is mapped by Author entity too. No need to create a persistence.xml or hibernate.cfg.xml files at this moment because the whole configuration will take place in the Spring files.

Create a DAOs

First of all create a generic DAO object to keep the reference to the EntityManager and avoid duplicate code in other DAOs.

package org.bserban.shs.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public abstract class GenericJPADAO<T, ID extends Serializable> {

private Class<T> persistentClass;

protected EntityManager em;

@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}

public EntityManager getEntityManager() {
return em;
}

public void save(T entity) {
getEntityManager().persist(entity);
}

public void delete(T entity) {
getEntityManager().remove(entity);
}
public T getById(Object id) {
return getEntityManager().find(persistentClass, id);
}

By making a generic DAO class using java generics we are avoiding casting and using the Object class as parameter, in this way our methods will always have the proper type for their operation. While this is very easy with simple application it can become more complicated, but don’t forget that now we are building bricks that will help us to build our house, for more complicated logic we just simply create a facade class that will use our bricks.
BookDAO.java and AuthorDAO.java

package org.bserban.shs.dao;
import org.bserban.shs.model.Author;
public class AuthorDAO extends GenericJPADAO<Author,Integer> {
}
package org.bserban.shs.dao;
import org.bserban.shs.model.Book;
public class BookDAO extends GenericJPADAO<Book,Integer>{
}

These classes are empty so far but specific methods will probably be added.

Create your service layer

I am going to build also a generic service similar with the generic DAO class. For this example I only need basic operations that can be easily made generic. All I need is to create a generic interface called GenericService and ask for a type. Note that while GenericService is an interface for the DAOs I’ve done an abstract class because I wanted to add code to methods.

package org.bserban.shs.service;
import java.util.List;
public interface GenericService<T> {
    T create(T entity);
    void delete(T entity);
    T update(T entity);
    List<T> list(int page, int size);
}

Now, in the Services classes we need to have also a reference to the specific DAO object for that type of service. I am going to create a dao field in each class and I am going to assume that somebody will set the dao to the correct value when the service will be used.

BookService.java and AuthorService.java, their structure is identically so i will list only one here:

package org.bserban.shs.service;
import org.bserban.shs.dao.AuthorDAO;
import org.bserban.shs.model.Author;
import java.util.List;
public class AuthorService implements GenericService<Author> {
    private AuthorDAO dao;
    public Author create(Author entity) {
        dao.save(entity);
        return entity;
    }
    public void delete(Author entity) {
        dao.delete(entity);
    }
    public Author update(Author entity) {
        dao.save(entity);
        return entity;
    }
    public List<Author> list(int page, int size) {
        return dao.list(page,size);
    }
    public AuthorDAO getDao() {
        return dao;
    }
    public void setDao(AuthorDAO dao) {
        this.dao = dao;
    }
}

For the listing feature I simply added a new method in the DAOs for list, and it looks like this:

................
public List<Author> list(int page, int size) {
    Query query = this.em.createQuery("from Author order by lastName,firstName");
    query.setFirstResult((page - 1) * size);
    query.setMaxResults(size);
    return query.getResultList();
}
.................
public List<Book> list(int page, int size) {
    Query query = this.em.createQuery("from Book order by title");
    query.setFirstResult((page - 1) * size);
    query.setMaxResults(size);
    return query.getResultList();
}
..................

Create the Actions

The actions are part of the controller and they need to validate data and to provide error handling before calling the service layer. One characteristic of putting together the Spring and Struts2 is that the dependency injection is done via a constructor argument. You could do it also with setters and getters but this would expose your service class to the exterior. One could call your action via HTTP by providing a parameter with the same name of your service class which will result into an unpredictable behavior, most probably an error.

In the actions I am going to have three fields, the first is the Service reference, the second is the list of model object and the third is a solo entity used for create, update, delete.

I will only list one Action class because they are pretty similar:

public class AuthorAction extends FrontendAction {
    private GenericService<Author> service;
    private List<Author> authors;
    private Author author;
    public AuthorAction(GenericService<Author> service) {
        this.service = service;
    }
    public String list() {
        authors=service.list(page, size);
        return SUCCESS;
    }
    public String update() {
        service.update(author);
        return SUCCESS;
    }
    public String create() {
        service.create(author);
        return SUCCESS;
    }
    public String delete() {
        service.delete(author);
        return SUCCESS;
    }
......................................

I have created a FrontendAction to put the page and size parameters, since they are a common feature of both actions.  Similar, you can put here other attributes that are common for the all actions.

Now lets add our actions into struts.xml file and start to configure the Spring support. I have chosen the extension of our actions to be *.html. I also want to set the Struts2 into dev mode to debug the application if necessary. For IOC Struts2 has a property called objectFactory which let’s you to specify what is your IOC container, i set this to “spring” values. The views will be written as Freemarker templates which I consider to be a powerful template engine.

<constant name="struts.devMode" value="true"/>
<constant name="struts.action.extension" value="html"/>
<constant name="struts.objectFactory" value="spring"/>
<constant name="struts.ui.theme" value="simple"/>
<constant name="struts.ui.templateSuffix" value="ftl"/>
<constant name="struts.configuration.xml.reload" value="true"/>

Now we need to declare our actions, I’ve decided to create different name space for each action which means that the http calls will look like this: /books/…..   /authors/…..

<package name="books" namespace="/books" extends="struts-default">
    <action name="list" class="bookAction" method="list">
        <result name="success" type="freemarker">/WEB-INF/pages/books/list.ftl</result>
    </action>
</package>
<package name="authors" namespace="/authors" extends="struts-default">
    <action name="list" class="authorAction" method="list">
        <result name="success" type="freemarker">/WEB-INF/pages/authors/list.ftl</result>
    </action>
</package>

For the purpose of demonstration I am providing only the listing capability, I let you code the rest. So I need to create two templates to list the entities, they are done in the same way so i am pasting only the author’s list page:

[#ftl]
<link media="screen" type="text/css" href="${base}/resources/css/style.css" rel="stylesheet">
<div>
<table class="listing">
    <tr><td class="hed" colspan="3">List of authors</td></tr>
    <tr>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Books</th>
    </tr>
    [#list authors as author]
    <tr [#if author_index%2 = 0]class="bg"[/#if]>
        <td>${author.firstName!''}</td>
        <td>${author.lastName!''}</td>
        <td>[#if author.books??][#list author.books as book] ${book.title}[#if book_has_next],[/#if][/#list][/#if]</td>
    </tr>
    [/#list]
</table>
</div>

Glue the code with Spring

This example uses Spring 2.5.5 version. I am going to separate the configuration files in two, one is for generic configuration for JPA and transactions and the second will contain our classes glued together.

My applicationContext.xml

Declare the JPA support

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

Now declare the EntityManager bean

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>
</bean>

The data source used by EntityManager bean

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/example" />
    <property name="username" value="example" />
    <property name="password" value="example" />
</bean>

Now I need to configure the transaction manager for my classes and obviously I am going to use the one that supports annotations. The era for declarative transaction configuration has long gone.

<bean id="transactionManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
<tx:annotation-driven transaction-manager="transactionManager" />

Let’s not forgot our objects, let’s tell Spring where is our application specific configuration file

<import resource="exampleContext.xml"/>
Now, all I need is to glue my classes together, basically our DAOs need the JPA beans, the Services need our DAOs and Struts Actions need our Services.
exampleContext.xml will contain the followings:
<!-- daos -->
 <bean id="authorDao" class="org.bserban.shs.dao.AuthorDAO"/>
 <bean id="bookDAO" class="org.bserban.shs.dao.BookDAO"/>
 <!-- services -->
 <bean id="authorService" class="org.bserban.shs.service.AuthorService">
     <property name="dao" ref="authorDao"/>
 </bean>
 <bean id="bookService" class="org.bserban.shs.service.BookService">
     <property name="dao" ref="bookDAO"/>
 </bean>
 <!-- action -->
 <bean id="authorAction" scope="prototype" class="org.bserban.shs.action.AuthorAction">
     <constructor-arg ref="authorService"/>
 </bean>
 <bean id="bookAction" scope="prototype" class="org.bserban.shs.action.BookAction">
     <constructor-arg ref="bookService"/>
 </bean>

Now add the transaction support to our service classes. I simply need to put the @Transactional annotation at class level which means that all method from that class support transactions.

import org.springframework.transaction.annotation.Transactional;
@Transactional
public class BookService implements GenericService<Book> {
.........................

I am going to configure also the web.xml file, where I’ll put the configuration for Struts and for Spring.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Now all we need is to hit run and see if it is working. Also we are going to need some testing data.

Database tables

Putting this line <property name=”generateDdl” value=”true” /> into EntintyManagerFactory bean configuration will cause the generation of our database tables.

tables

I just need to insert manually some sample data to be able to list them in the “list” pages.

Sample data:

INSERT INTO `author` (`id`,`firstName`,`lastName`,`blog`) VALUES  (1,'John','Doe','no blog'), (2,'Sam','Dune','no blog');
INSERT INTO `book` (`id`,`title`,`publisher`,`keywords`,`ISBN13`,`ISBN10`) VALUES  (1,'Some Random Title','The plublisher','random','0596517726','978-0596517724');
INSERT INTO `book_author` (`books_id`,`authors_id`) VALUES  (1,1);

Html Views

Let’s add a simple css file to give a decent look to our pages, all we need is to customize the table look&feel.

table.listing {
    text-align: center;
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
    font-weight: normal;
    font-size: 11px;
    color: #fff;
    width: 280px;
    background-color: #666;
    border: 0px;
    border-collapse: collapse;
    border-spacing: 0px;
}
table.listing td {
    background-color: #CCC;
    color: #000;
    padding: 4px;
    text-align: left;
    border: 1px #fff solid;
}
table.listing td.hed {
    background-color: #666;
    color: #fff;
    padding: 4px;
    text-align: left;
    border-bottom: 2px #fff solid;
    font-size: 12px;
    font-weight: bold;

End the result:

http://localhost:8080/books/list.html

listBooks

http://localhost:8080/authors/list.html

listAuthors

I hope I’ll have the time to continue this apps and introduce jQuery for simple actions like add/edit/delete/filter books and authors.

Cheers,

Resources

I’ll list here all the needed jars/frameworks for this sample application:

Source code sample, you can downloaded from here Struts2, Spring, JPA, Hibernate