Annotation Driven JSF-Spring-JPA

JSF-Spring-JPA is the popular stack of choice these days, mostly to be used in my consulting and training purposes I’ve created a base project called MovieStore demonstrating the annotation-driven integration of JSF-Spring-JPA. JSF backing beans, spring service level beans and DAO’s are configured and integrated with annotations. Only the core infrastructure like datasource, entityManagerFactory or transactionManager are configured with xml.

Following are the package contents;

– JSF (MyFaces 1.2.2 with Facelets)
– Spring 2.5
– JPA with Hibernate
– HSQLDB for persistence
– Jetty for deployment
– Maven2 for build

The example application is simple; a MovieStore(Yes, I’m a movie maniac so all my examples are about movies)
There are two formats DVD and BLU-RAY, not including HD-DVD because it’s dead.

Movie

package com.prime.tutorial.moviestore.domain;

//imports not displayed

@Entity
public class Movie implements Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Basic
    private String title;

    @Basic
    private Integer discs;

    @Enumerated
    private Format format;

    public Movie() {}

    public Movie(String title, Integer discs) {
        this.title = title;
        this.discs = discs;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Integer getDiscs() {
        return discs;
    }
    public void setDiscs(Integer discs) {
        this.discs = discs;
    }

    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }

    public Format getFormat() {
        return format;
    }
    public void setFormat(Format format) {
        this.format = format;
    }
}

For DAO part, I’ve included a GenericDAO too for the crud operations;

package com.prime.tutorial.moviestore.dao;

//imports are not displayed

public interface GenericDAO<t, ID extends Serializable> {

	T loadById(ID id);

	void persist(T entity);

	void update(T entity);

	void delete(T entity);

	List<t> loadAll();

}

Following is the GenericDAO implementation with JPA, note how the entityManager is injected. Instead of extending JPATemplate, with @PersistenceContext, the entityManager is resolved by spring. This way you don’t need to subclass JPATemplate.

package com.prime.tutorial.moviestore.dao;

//imports are not displayed
public abstract class GenericDAOWithJPA<t, ID extends Serializable> implements GenericDAO<t,ID> {

	 	private Class<t> persistentClass;

	 	@PersistenceContext
	 	protected EntityManager entityManager;

	 	@SuppressWarnings("unchecked")
	    public GenericDAOWithJPA() {
	        this.persistentClass = (Class<t>) ((ParameterizedType) getClass()
	                                .getGenericSuperclass()).getActualTypeArguments()[0];
	    }

	    public Class<t> getPersistentClass() {
	        return persistentClass;
	    }

	    public T loadById(ID id) {
	       return entityManager.find(persistentClass, id);
	    }

	    public void persist(T entity) {
	        entityManager.persist(entity);
	    }

	    public void update(T entity) {
	        entityManager.merge(entity);
	    }

	    public void delete(T entity) {
	        entityManager.remove(entity);
	    }

	    @SuppressWarnings("unchecked")
	    public List<t> loadAll() {
	        return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").getResultList();
	    }
}

That’s all about the GenericDAO, for movie specific database operations here comes the MovieDAO.

MovieDAO

package com.prime.tutorial.moviestore.dao;

//imports not displayed

public interface MovieDAO extends GenericDAO{

    public List findByTitle(String title);
}

MovieDAOWithJPA is annotated with @Repository, by this way spring can manage it and can also allows ExceptionTranslation(PersistenceAnnotationBeanPostProcessor also needs to be configured in applicationContext.xml).

package com.prime.tutorial.moviestore.dao;

//imports not displayed

@Repository
public class MovieDAOWithJPA extends GenericDAOWithJPA implements MovieDAO{

    @SuppressWarnings("unchecked")
    public List findByTitle(String title) {
        Query query = entityManager.createQuery("Select m from Movie m where m.title = ?1");
        query.setParameter(1, title);

        return query.getResultList();
    }

}

At service level there are two classes, MovieService and MovieServiceImpl.

MovieService – Notice the @Transactional annotation, this way transactions are configured with annotations.(<tx:annotation-driven /> also needs to be declared to enable this, see applicationContext.xml)

package com.prime.tutorial.moviestore.service;

//imports not displayed

public interface MovieService {

    public void createNew(Movie movie);

    public List findAll();

    public List findByTitle(String title);
}

MovieServiceImpl @Service annotation makes this a spring bean, and movieDAO is injected by type using @AutoWired

package com.prime.tutorial.moviestore.service;

//imports not displayed

@Service
public class MovieServiceImpl implements MovieService{

    private MovieDAO movieDAO;

    @Autowired
    public MovieServiceImpl(MovieDAO movieDAO) {
        this.movieDAO = movieDAO;
    }

    @Transactional
    public void createNew(Movie movie) {
        movieDAO.persist(movie);
    }

    public List findAll() {
        return movieDAO.loadAll();
    }

    public List findByTitle(String title) {
        return movieDAO.findByTitle(title);
    }
}

Finally the JSF Bean and Facelets page to use the stuff above, the page is used for creating new movies.

createMovie.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	template="template.xhtml">

  <ui:define name="content">
	<h:messages showDetail="true"/>
	<h:form>
		<h:panelGrid columns="2">
			<h:outputLabel for="title" value="Title"></h:outputLabel>
			<h:inputText id="title" value="#{createMovie.movie.title}"></h:inputText>

			<h:outputLabel for="discs" value="Number of Discs"></h:outputLabel>
			<h:inputText id="discs" value="#{createMovie.movie.discs}"></h:inputText>

			<h:outputLabel for="format" value="Format"></h:outputLabel>
			<h:selectOneMenu id="format" value="#{createMovie.movie.format}">
				<f:selectItem itemLabel="DVD" itemValue="DVD" />
				<f:selectItem itemLabel="BLU-RAY" itemValue="BLURAY" />
			</h:selectOneMenu>
		</h:panelGrid>
		<h:commandButton value="Save" action="#{createMovie.save}"></h:commandButton>
	</h:form>
  </ui:define>

</ui:composition>

CreateMovie is the backing bean to handle this page, also managed by spring. The MovieService is set through construction injection, one thing you cannot do in plain jsf ioc. @Component marks this bean as a spring bean with the “createMovie” name. In jsf views, this is the name to be resolved in el expressions like #{createMovie.movie.title}. @Scope is set to request, as you may already know with spring it’s also possible to provide custom scopes.

package com.prime.tutorial.moviestore.view;

//imports not displayed

@Component("createMovie")
@Scope("request")
public class CreateMovie implements Serializable{

    private MovieService movieService;

    private Movie movie = new Movie();

    @Autowired
    public CreateMovie(MovieService movieService) {
        this.movieService = movieService;
    }

    public Movie getMovie() {
        return movie;
    }
    public void setMovie(Movie movie) {
        this.movie = movie;
    }

    public String save() {
        movieService.createNew(movie);
        FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, "Movie is saved successfully", "OK");
        FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        movie = new Movie();

        return null;
    }
}

So where’s the xml? Let’s start with the spring config.

applicationContext.xml

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<context:property-placeholder location="classpath:application.properties"/>
	<context:component-scan base-package="com.prime.tutorial.moviestore" />
	<tx:annotation-driven transaction-manager="txManager"/>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="moviestore"/>
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="databasePlatform" value="${database.dialect}"/>
				<property name="showSql" value="${database.showSql}" />
				<property name="generateDdl" value="${database.generateDdl}" />
			</bean>
		</property>
	</bean>

	 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
        <property name="driverClassName" value="${database.driver}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
    </bean>

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

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

</beans>

Notes on spring config;
<context:component-scan base-package=”com.prime.tutorial.moviestore” /> scans the moviestore sub packages for annotated classes, with this it can find our jsf beans, services, daos and etc.
<tx:annotation-driven transaction-manager=”txManager”/> enables annotation driven transaction management
PersistenceAnnotationBeanPostProcessor is for exception translation, we don’t extend from JPATemplate but we can still have this feature.

persistence.xml

<?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="moviestore" transaction-type="RESOURCE_LOCAL">
		  <class>com.prime.tutorial.moviestore.domain.Movie</class>
	</persistence-unit>

</persistence>

faces-config.xml – Pretty empty:)

<?xml version="1.0" encoding="utf-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
	version="1.2">

	<application>
		<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
		<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
	</application>

</faces-config>

– DelegatingVariableResolver helps JSF to resolve spring managed beans like CreateMovie.

Finally the web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
	version="2.4">

	<context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>client</param-value>
	</context-param>

	<context-param>
		<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
		<param-value>.xhtml</param-value>
	</context-param>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<listener>
		<listener-class>
			org.springframework.web.context.request.RequestContextListener
		</listener-class>
	</listener>

	<filter>
		<filter-name>JPA Filter</filter-name>
		<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>JPA Filter</filter-name>
		<url-pattern>*.jsf</url-pattern>
	</filter-mapping>

	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
</web-app>

– org.springframework.web.context.request.RequestContextListener listener enables spring scopes with @Scope annotation

– JPA Filter is same as OpenSessionInViewFilter but for jpa.

Testing

I’ve also included an integration test for MovieDAOWithJPA, it does not subclass AbstractJPATests and configured completely on spring’s annotation support for testing.

package com.prime.tutorial.moviestore.dao;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.prime.tutorial.moviestore.domain.Movie;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@TransactionConfiguration(transactionManager="txManager")
@ContextConfiguration(locations={"/applicationContext.xml"})
public class MovieDAOWithJPATest{

    private MovieDAO movieDAO;

    @Autowired
    public void setRepository(MovieDAO movieDAO) {
        this.movieDAO = movieDAO;
    }

    @Test
    public void shouldPersistNewMovie() {
        Movie movie = new Movie();
        movie.setTitle("Scarface");
        movie.setDiscs(new Integer(2));

        movieDAO.persist(movie);

        assertNotNull(movie.getId());
    }

    @Test
    public void shouldFindByTitle() {
        Movie movie = new Movie();
        movie.setTitle("Carlito's Way");
        movie.setDiscs(new Integer(1));

        movieDAO.persist(movie);
        assertNotNull(movie.getId());

        List results = movieDAO.findByTitle("Carlito's Way");
        assertEquals(1, results.size());
        assertEquals("Carlito's Way", results.get(0).getTitle());
    }

    @Test
    public void shouldReadAllMovies() {
        Movie movie1 = new Movie();
        movie1.setTitle("Godfather Part I");
        movie1.setDiscs(new Integer(1));

        Movie movie2 = new Movie();
        movie2.setTitle("Godfather Part II");
        movie2.setDiscs(new Integer(1));

        movieDAO.persist(movie1);
        assertNotNull(movie1.getId());

        movieDAO.persist(movie2);
        assertNotNull(movie2.getId());

        List results = movieDAO.loadAll();
        assertEquals(2, results.size());
    }
}

I’ve packaged my moviestore example and uploaded to http://people.apache.org/~cagatay/moviestore.rar, build is based on maven2 and you can easily get it running with;

mvn jetty:run

And then go to -> http://localhost:8080/moviestore

The database is hsqldb with inmemory setting.Final words;
I’ve actually created this sample app to be used in my consulting work but if you’ve decided to go with JSF-Spring-JPA, it is definitely a good resource for kickstart.

19 Responses to Annotation Driven JSF-Spring-JPA

  1. Good post! We are working on a similar thing for JPA, JSF and Spring 2.5. We are writing a series of articles for IBM devWork on combing the three tehnologies.

    Good stuff Catagay. Thanks. You rock!

  2. Doug says:

    Nice post. Quick question – how do you define ‘ID’ in GenericDAO:


    T loadById(ID id);

  3. Chris says:

    Tags are not appearing for me in all your references to xml files in this tutorial. I tried viewing this page on Safari 3.0 & Firefox 2.0 for Mac OS 10.5.

    Can you escape these tags so I can see what goes where?

  4. Hasan Basri says:

    Merhabaler Ça?atay Bey,
    Öncelikle elinize sa?l?k güzel bir çal??ma olmu?.

    projeyi deniyorum ama ?öye bir hata ald?m neden olabilir. uzun olmas?n diye sadece ilgili dat?r? yaz?yorum

    Te?ekkürler

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: No persistence unit with name ‘moviestore’ found

  5. Because of @Transaction: from the spring reference manual: “you must annotate the implementation class (and/or methods within that class), not the interface”

  6. Johnny Mongiat says:

    Always nice to see a post detailing the JSF/Spring/JPA stack (YES, ‘standard’ and ‘non-standard’ technologies can definitely co-exist). We are actually refactoring an existing application (Struts + J2EE 1.4) to an annotation driven JSF/Spring/JPA architecture, and so far the experience has been gratifying (especially from a configuration standpoint – it is a complete myth that Spring is XML heavy).

    I highly recommend (if not turned off by JSF) to look into JSF/Spring/JPA and/or Seam as viable options.

    Cheers.

  7. cagataycivici says:

    Updated entry, add syntax fixes, html escapes and more…

  8. If you get some noise from maven about not being able to find the jta jar see this.

  9. Pingback: Annotation Driven JSF-Spring-JPA « Cagatay Civici’s Weblog

  10. Pingback: JSF vs Wicket, Job Opportunities « Cagatay Civici’s Weblog

  11. Brian Kates says:

    Hey Cagatay Civici, this is a little off topic, but I’m not sure where else to post it. I found a bug (NullPointerException) in ChartCreator. Whenever I try to view a generated image in FireFox (right click -> view image), it crashes (NullPointer). Is this a known issue? Is there a fix? Is there a better forum to discuss this? Feel free to email me if you wish. Thanks.

    -Brian

  12. Aykut Soysal says:

    selam cagatay bey,
    ben verdiginiz bu ornegi netbeans ile glassfish v2 app server uzerinde deniyim dedim. olmadi🙂
    deploy ederken glassfish persistance-unit’in tipinin JTA olmasi istiyor. JTA yapinca bu sefer hibernate “org.hibernate.HibernateException: The chosen transaction strategy requires access to the JTA TransactionManager” gibi bir hata veriyor. acaba bir fikriniz var mi bu konuda?

  13. Excelente post, es uno de los pocos recursos claros acerca del uso de anotaciones en JSF que no usa Jboss Seam…Gracias.

  14. pablo borges says:

    congratulations on tutorial. very well written.🙂

  15. Thanks for this, Cagatay! This allowed me to add Spring and JPA to my JSF app very quickly. I find I like container-managed transactions more than I thought I would. Special thanks for making all the source code available. This is a fantastic way to get started.

  16. Mohammad says:

    first of all, many thanx for this good article…
    I did download the source code and I tried to run the “MovieDAOWithJPATest” but the following exception appear:

    ### Start ###
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified..
    ### End ###

    your help is appreciated..
    Mohammad

  17. Maryam says:

    Hello and thanks for your clean and practical tutorial sample.
    But I have a problem in my sample .I followed all your steps but unfortunately I have exception when I use data Table tag either with or with
    .my list which is filled in my action has its value but the properties which are in my entity aren’t shown!
    Would you please give me the exact Jar File which you have used with this sample.

  18. peperolo says:

    Thanks for the excellent tutorial. Very useful

%d bloggers like this: