A Struts 2, Spring, and Hibernate Example Application

Introduction

I was learning Hibernate as another methodology for storing my Java objects' state in a data repository. I wanted to experiment with integrating Hibernate into a Struts 2 and Spring application so I created an example of using the three technologies together. The combination of these three frameworks enables Java developers to create powerful web applications with a minimum of code.

Example Application

Download the example application.

The example application was created using Eclipse 3.5 with the Maven 2 plugin. The JDK used was JVM 1.6 on the Mac. The application uses Maven to manage its Jar dependencies. Please note the example application is partially based on one of the Hibernate examples provided in Cameron McKenzie's excellent Hibernate Made Easy book.

The application uses an in-memory database (HSQL) that is setup by the Spring applicationContext.xml class. See files schema.sql and test-data.sql in src/main/resources for the schema created during the application's startup and the initial records inserted into the table's database. Using the in-memory database means there is no need to setup and run a separate database server for the example application.

You can import this project into Eclipse by using Eclipse's File - Import feature. In the project's root folder is a README.txt file that explains how to run the application.

NOTE the example application was updated in October 2010 to use the latest versions of the Struts and Spring jars and to use Spring 3.0's ability to create an in-memory HSQL database.

If you're not using Eclipse 3.5 with the Maven 2 plugin, you can unzip the archived download and view the source code in any text editor. If you are using a Java IDE that enables importing of Maven projects you should be able to import the unzipped project.

You can also run the application using Maven directly if you have downloaded and installed Maven on your computer. Open a terminal (command) window and navigate to the project's root folder (the folder where pom.xml resides). Then in the terminal window issue these commands:

mvn clean
mvn test (All 7 tests should pass successfully).
mvn jetty:run

When you see [INFO] Started Jetty Server open a web browser and navigate to http://localhost:8080/Struts2_Spring_Hibernate_Example/index.html

To stop the Jetty web server type CTRL-C in the terminal window.

Implementing Hibernate

To implement Hibernate, I use the Java Persistence API (JPA) annotations (@Entity, @Column, @Table, etc) to provide Hibernate the information it needs to map my model object to a table and columns in the database schema. I also have my Data Access Object (DAO) extend Spring's HibernateDaoSupport class so that I can easily inject a Hibernate SessionFactory into the DAO. I also use Spring's @Transactional annotation to mark the methods of my DAO as occurring in a single transaction.

Note there are several different ways to integrate Spring and Hibernate. My example's methodology may not be the best one. Consult the Spring references below for other ways to use Spring and Hibernate together.

Integrating Struts 2, Spring, and Hibernate

The key to effectively using Struts 2 with Hibernate is to properly layer (Presentation, Action, Service, DAO) your application. In my example, the Struts 2 ActionSupport classes are ignorant of how Java objects are provided. The Struts 2 ActionSupport class makes calls to a Service class (injected by Spring). The Service class makes calls to the DAO class (injected by Spring) which uses Hibernate to get data out of and into the data repository and to translate the data into and out of Java objects.

All concrete classes implement an Interface and any class referenced as part of another class is referenced by its Interface type. This makes the overall application easier to maintain, test, and enhance in the future.

The concrete HibernateDaoSupport classes receive their Hibernate SessionFactory objects injected by Spring. The SessionFactory object receives its DataSource object injected by Spring. See the Spring applicationContext.xml for the creation of these Spring-managed beans.

Summary

There is a steep learning curve in becoming comfortable using these complex frameworks. You're not going to learn Struts 2, Spring, and Hibernate overnight. Leveraging these technologies requires studying good books, online references, and example applications. The references I've listed below, are ones I've found useful in learning Struts 2, Spring, and Hibernate.

Of course this blog article is not going to be able to teach anyone everything (anything?) involved in integrating these three technologies. Consult the references below for where to go to learn more. I do hope my example application will be useful to others learning Hibernate and who want to integrate Hibernate into a Struts 2 and Spring application.

References:

  1. Hibernate Made Easy, Cameron McKenzie, 2008, http://www.hiberbook.com/
  2. Hibernate Documentation, https://www.hibernate.org/5.html
  3. Spring Recipes (chapter 9), Gary Mak, 2008 Apress, http://www.apress.com/book/view/9781590599792
  4. Pro Spring 2.5 (chapter 11), Jan Machacek, Aleksa Vukotic, and others, 2008 Apress, http://www.apress.com/book/view/9781590599211
  5. Spring Framework - http://www.springsource.org/documentation
  6. Spring Community Forums - http://forum.springsource.org/
  7. Introduction to the Spring Framework 2.5 - http://www.theserverside.com/tt/articles/article.tss?l=IntrotoSpring25
  8. Spring in Action, 2nd Edition, Manning Publishing, August 2007
  9. Struts 2 Framework - http://struts.apache.org
  10. Using Struts 2 and Spring Frameworks Together, Bruce Phillips Blog - http://www.brucephillips.name/blog/index.cfm/2008/10/17/Using-Struts-2-and-Spring-Frameworks-Together
  11. Struts 2 In Practice, Manning Publishing, http://www.manning.com/wannemacher/
  12. Apache Struts 2 Documentation, Spring Plugin - http://struts.apache.org/2.x/docs/spring-plugin.html
  13. Struts 2 In Action, Donald Brown, 2008 Manning, http://www.manning.com/dbrown/
  14. Apache Struts 2 Web Application Development, Dave Newton, 2009 Packt, http://www.packtpub.com/apache-struts-2-web-application-development-beginners-guide/book
  15. Struts User Forum - http://www.nabble.com/Struts---User-f206.html
  16. Maven - http://maven.apache.org/
  17. Maven - http://books.sonatype.com/maven-book/index.html

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Hi Bruce! I'm writing from Argentina. I just want you to know that I appreciate your examples and your willing to share what you learn. It is great that you keep on learning and enjoy software developing.
I hope to have a web someday and to be able to give at least a small part o what I've learned.
Thank you! maintain that attitude! Sorry if my english sucks!
# Posted By Mauro | 7/23/10 10:25 PM
I tried to get the example work and found that http://repo1.maven.org/maven2/javax/transaction/jt... is no more available, so
I downloaded it from http://download.java.net/maven/2/javax/transaction..., made mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar -Dfile=/download_path/jta-1.0.1B.jar, and now is working from command line.

Thank you very much.
# Posted By Hisie | 11/17/10 8:23 AM
Hisie - thank you for letting me know there was a problem in the transitive dependencies in my pom.xml. I updated the pom.xml to a newer version of Hibernate and that eliminated the transitive dependency issue you described.

If anyone has any issues with the download please let me know.

Bruce
# Posted By Bruce | 11/17/10 9:15 AM
Hi,
first of all thank you for sharing knowledge.
I'm curious, how would u implement localization in this example?
I'm asking because afaik this is only way to getText() method working properly, but
on expense of localization via request_locale parameter.
On other hand i might be missing something due to being newbie to spring and i'd be glad to get some hints.

Thank you & Best regards
Miha
# Posted By Miha | 11/25/10 7:28 AM
Mihia - I use Struts 2 for localization. See: http://struts.apache.org/2.2.1/docs/message-resour...
# Posted By Bruce | 12/1/10 6:45 AM
Hi, your test cases are working, but not the application, something
wrong with the spring imp on applicationContext.xml. would be good
if someone can help fixing it.
# Posted By dylan | 6/13/11 7:08 PM
dylan - thanks for letting me know. I think I've got it corrected and uploaded a new version of the example. There was a transitivie dependency that was bringing in an older version of Hibernate that was causing a class conflict with the newer version of Hibernate.
# Posted By Bruce | 6/13/11 7:54 PM
Hi Bruce,

Thanks very much for your example. I have downloaded it but when I run it on Tomcat by Run As -> Run on Server. I got this exception. Would you like to have a look at this one? Thanks very much.

2011-08-05 20:08:55,097 ERROR org.springframework.web.context.ContextLoader.initWebApplicationContext:220 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IncompatibleClassChangeError: Implementing class
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
   at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:710)
   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:410)
   at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276)
   at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197)
   at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
   at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4205)
   at org.apache.catalina.core.StandardContext.start(StandardContext.java:4704)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
   at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
   at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
   at org.apache.catalina.core.StandardService.start(StandardService.java:525)
   at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
   at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
   at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IncompatibleClassChangeError: Implementing class
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
   at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:398)
   at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:275)
   at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:122)
   at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:78)
   at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70)
   at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:96)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1439)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1408)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
   ... 25 more
Caused by: java.lang.IncompatibleClassChangeError: Implementing class
   at java.lang.ClassLoader.defineClass1(Native Method)
   at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
   at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
   at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
   at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
   at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159)
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647)
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
   at java.lang.Class.getDeclaredConstructors0(Native Method)
   at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
   at java.lang.Class.getConstructor0(Class.java:2699)
   at java.lang.Class.getDeclaredConstructor(Class.java:1985)
   at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:104)
   at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newConfiguration(LocalSessionFactoryBean.java:779)
   at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:561)
   at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:134)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
   ... 40 more
# Posted By Vu Pham | 8/5/11 7:24 AM
Vu - I downloaded the example, unzipped it, and ran the mvn commands mentioned in the article. Everything worked.

I then ran mvn package to create the war file. I moved the war file to Tomcat webapps and started up Tomcat. I get the same error as you.

I updated the Hibernate dependency to 3.5.6-Final, re-ran mvn clean package. I deployed the new war file to tomcat and everything worked.

So I think the previous version may have caused a class-loader issue with Tomcat but not Jetty.

I uploaded a new zip so download that one and give it a try.

Bruce
# Posted By Bruce | 8/5/11 7:59 AM
Thanks Bruce. It's working perfectly now :-)
# Posted By Vu Pham | 8/7/11 10:30 PM
Hi Bruce,

I ran mvn package to create a war file and deploy it to Tomcat 6. There was no problem.
But when I tried to run in Eclipse with Debug As -> Debug on Server, I got below errors. It seemed the classes/lib could not be deployed to Tomcat in this way. Do you have any idea? Thanks.

Oct 1, 2011 3:00:24 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
   at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4149)
   at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
   at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
   at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
   at org.apache.catalina.core.StandardService.start(StandardService.java:525)
   at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
   at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
   at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Oct 1, 2011 3:00:24 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Error configuring application listener of class org.springframework.web.context.request.RequestContextListener
java.lang.ClassNotFoundException: org.springframework.web.context.request.RequestContextListener
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)
   at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
   at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4149)
   at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
   at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
   at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
   at org.apache.catalina.core.StandardService.start(StandardService.java:525)
   at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
   at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
   at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
# Posted By Risenote | 9/30/11 2:04 PM
Risenote - Since Maven is being used to manage classpath dependencies you need to run a Maven command that will create the classpath dependency information for Eclipse's Web Tools Project. Try running this maven command at the command line in the project's root folder:

mvn -e eclipse:eclipse -Dwtpversion-1.5

Then open the project up in an Eclipse workspace. By default there are problems between Eclipse's Web Tools Project and Maven.
# Posted By Bruce | 10/10/11 8:47 AM
Bruce, thanks a lot for your help. You solved my problem with this simple command. I haven't used Maven before, so I definitely need to spend some time to study about this tool later.

BTW, there was a typo that the sign after -Dwtpversion should be '=' instead of '-'.

Eric
# Posted By Risenote | 10/10/11 12:34 PM
Hi Bruce,
thanks for the tutorial. Can you please let me know how to configure this to connect to a MYSQL DB?

thanks
# Posted By Doug | 2/19/12 12:49 AM
Doug - Read through the Spring documentation at: http://static.springsource.org/spring/docs/3.0.x/s...

See section 12.3. Controlling database connections and if you want to use a JNDI reference see C.2.3. The jee schema.
# Posted By Bruce | 2/19/12 8:50 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner