I've created an example application that uses Struts 2, Spring 3, JPA 2, Hibernate 3.5, and Maven. I need some advice from Java web application developers who are using Spring 3, JPA 2, and Maven. The programming team I'm part of is moving to JPA. We plan to use Hibernate as the JPA provider but we want to keep the dependency on Hibernate to a minimum. To reduce our direct dependency on Hibernate we are using the Spring - JPA configuration described in chapter 4 of Spring Persistence with Hibernate and in section 13.5 of the Spring 3 documentation (see references below). I've run into an issue with configuring my applications to follow this structure and I'd appreciate any advice from Java developers more experienced with Spring, JPA, and Maven.
Please download the example application. It is a standard Maven project, created using Eclipse 3.6. 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. If you're not using Eclipse 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 tests should pass successfully)
- mvn jetty:run
When you see [INFO] Started Jetty Server open a web browser and navigate to http://localhost:8080/strutsspringjpaexample/index.jsp. Enter 1, 2, or 3 in the employee id text field and click submit.
To stop the Jetty web server type CTRL-C in the terminal window.
Based on the goal of reducing the direct dependency on Hibernate, the application uses the configuration described in section 13.5 of the Spring 3.0 documentation (reference 2) to setup Spring integration with JPA. The Spring configuration file creates an LocalContainerEntityManagerFactoryBean object and provides it with the data source, location of the persistence.xml file, and the name of the persistence unit to use.
The persistence.xml file defines the persistence unit including what classes are to be JPA entities, what is the JPA provider (Hibernate), and the properties for the JPA provider.
The model classes use JPA 2 annotations to identify how a model class is related to a database table.
The data access classes use Spring's @Repository annotation to mark the class as one Spring should automatically create an instance of in the Inversion of Control container. In the Spring configuration file are these nodes which are used with @Repository:
<!-- scans the classpath for annotated components (including @Repository) that will be
auto-registered as Spring beans -->
<context:component-scan base-package="edu.ku.it.si.springjpaexample.dao" />
<!-- This will ensure that hibernate or jpa exceptions are automatically translated into
Spring's generic DataAccessException hierarchy for those classes annotated with Repository
For example see PersonDaoJpa-->
The data access classes also use the JPA @PersistenceContext annotation to mark which method Spring should use to inject the EntityManager object into the data access class. The data access classes then use the EntityManager object to create queries that will run against the database and return model objects.
Note that the data access classes do not extend any other class and are not tied to Hibernate. The model and data access classes only use JPA 2 annotations. No Hibernate configuration files are needed. The Hibernate properties are set in the pesistence.xml file. As I understand it as long as our classes use JPA 2 annotations, I should be able to change JPA providers (say from Hibernate to OpenJPA) by just changing the persistence.xml file.
The service classes use Spring's @Service annotation to mark the class as one Spring should automatically create an instance of in the Inversion of Control container. Using the Struts 2 Spring plugin (see the pom.xml) will cause Spring to inject the services classes into the Struts 2 Action Support classes.
In the service classes any data access classes needed are annotated with Spring's @Autowired annotation.
Tomcat Issues With Spring - JPA Project
My company uses Tomcat 6 as its Servlet container. When deploying the war file created by my example application I get this warning:
WARN org.hibernate.ejb.packaging.InputStreamZippedJarVisitor.doProcessElements:61 -
Unable to find file (ignored): jndi:/localhost/strutsspringjpaexample/
I think this is from a bug in the Hibernate code, as the application works fine. I researched the error on the internet and only found one reference that might be applicable (see reference 3). But if anyone has more insight on why this warning is generated and if there is something I need to configure differently please comment.
Request For Advice
My programming team is exploring the best way to structure our Spring - JPA web applications. I've created an example application that demonstrates one way to structure the application. Before recommending this structure to my team I'd like to get input from more experienced Java developers.
I'd appreciate any advice and comments from other Java developers who have experience with Spring - JPA - Maven web applications on the best way to structure the application.
- Spring Persistence with Hibernate; Paul Tepper Fisher and Brian D. Murphy; Apress Publishing, 2010
- Section 13.5 JPA, Spring Framework Reference Documentation 3.0
- Thread Discussion On Hibernate Application Startup