Spring and Hibernate with Annotations

I have to admit it. I had the worst time with Hibernate when I first started learning it a few years ago.  Although I could see the power, the configuration inside Spring was a bit of a nightmare back then.

Today, both Spring and Hibernate support annotation-based configuration, which makes the whole process easier.  Combine this with Hibernate’s Auto-DDL ability (that is, automatic table creation), and it is quite simple to use Hibernate with Spring as long as you follow a few conventions.

The purpose of this article is to build a Hibernate managed Spring web application.  Here are the primary goals:

  • No SQL scripts, not even table creation scripts
  • Minimum XML configuration
  • Relationships defined by Java Persistence API (JPA) annotations
  • Read, write and edit two related classes
  • Make the framework extensible for adding other classes with minimal work

Full source code for this tutorial is available here.

UPDATE March 2014: This code is also available in GitHub at https://github.com/technologicaloddity/departments

Interested? Read on…

What you will need (if you are going to follow along):

  • a MySQL database. Note that this tutorial may work with other database systems (with a small configuration change), but I’ve only tested it with MySQL.
  • Eclipse (I’m using 3.5.2 “Galileo”, but earlier versions should be OK)
  • Maven and the Maven Eclipse plug-in
  • The Java Development Kit, version 6+
  • Some basic knowledge about the Spring Framework and how it works
  • Hibernate3+. We’ll add this as a Maven dependency so don’t worry about downloading it.
  • General HTML and JSP knowledge.

Our application will have two first-level classes: Employee and Department.  Each Employee may be attached to any number of Departments, and Departments may contain any number of Employees.  We will be able to add, edit and delete both Employees and Departments at any time.

Please note that I am no Spring expert and certainly no expert in Hibernate.  For any given application, there are probably better or more efficient ways to do things.  The purpose of this post is to provide exposure to what is possible in Spring and Hibernate.  My philosophy is to go over everything line-by-line and show ALL files, and how they fit together.  If you feel I’ve forgotten something or done something badly, I encourage you to add it in the comments so that we can all learn from it.

Setting Up the Web App Structure

First, let’s create our project in Eclipse.  Select File > New > Project > Maven Project from the menu.  Select the “maven-archetype-webapp” archetype from the selection box, click next, and name the project “departments”.  Note: if you need a bit more hand-holding creating the Maven project, see my post on Creating a HelloWorld Web App, which has more detailed directions.

NewMavenWebProject

Now let’s set up our web.xml file (located at /src/main/webapp/WEB-INF/web.xml in the project).

/src/main/webapp/WEB-INF/web.xml

<web-app id="WebApp_ID" version="2.4"
    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">

    <display-name>Departments webapp</display-name>

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>departments.root</param-value>
    </context-param>

    <listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener>

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

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/spring/dispatch-servlet.xml
        </param-value>
    </context-param>
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>

    <servlet>
        <servlet-name>dispatch</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:/spring/dispatch-servlet.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatch</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>        

    <servlet-mapping>
        <servlet-name>dispatch</servlet-name>
        <url-pattern>/index.html</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>    

</web-app>

This is a fairly standard 2.4 web application configuration file with Spring defined.  Let’s go through it line by line.

  • Lines 1-4: The standard XML namespace definition for web.xml 2.4.
  • Line 5: The name of the webapp as it will appear in management consoles (like Tomcat manager)
  • Lines 7-10: A context parameter, which helps to segment the departments web application from other applications running on the same server.
  • Lines 12-18: The Spring Log4J listener, which allows Spring to configure and use Log4J.
  • Lines 20-25: This defines where the Spring XML configuration file is located relative to the classpath. Note that /spring/dispatch-servlet.xml maps to /src/main/resources/spring/dispatch-servlet.xml in the project structure.
  • Lines 26-29: The location of the log4j.properties file (which maps to /src/main/webapp/WEB-INF/log4j.properties for us).
  • Lines 31-41: Load the Spring dispatcher servlet, through which all Spring requests are processed.
  • Lines 43-51: These are the mappings for Spring.  We will capture all calls to *.html, plus an extra mapping specifically for index.html. Why the extra index.html mapping?  Read this post to find out.
  • Lines 53-55: The standard web app welcome file.
  • Line 57: The XML closing tag.

Set Up MySQL Database

The setup for MySQL is quite easy.  Simply create a database named “departments”, and make sure you have a user assigned to it.  If you are using XAMPP (which I highly recommend), then user “root” with no password will already have access to “departments”.  Note that we don’t need to add any tables or structure here yet.  Hibernate will handle that for us.

Set Up the Maven pom.xml

Every Maven project needs a pom.xml file.  It will define the build type and dependencies that are needed to run the program.  If you want to know a bit more about Maven, you can see my Spring and Maven Webapp post.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.technologicaloddity</groupId>
  <artifactId>departments</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>departments Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>3.3.2.GA</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-annotations</artifactId>
        <version>3.4.0.GA</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.14</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>3.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-jdk14</artifactId>
        <version>1.5.10</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.8.0.GA</version>
    </dependency>
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.1.2</version>
    </dependency>
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2</version>
    </dependency>
  </dependencies>
  <build>
      <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
<finalName>departments</finalName>
</build> </project>

This is a fairly straight-forward pom.xml file for a WebArchive (WAR) project.  Instead of a line-by-line, lets look at each of the dependencies and why they are necessary to the project.

  • hibernate-core: provides the basic functions needed by all Hibernate applications
  • hibernate-annotations: We will be using a mix of Spring, Hibernate, and JPA annotations in the project.
  • spring-webmvc: We will build our webapp using simple Spring Web MVC.  I’m using the newest version as of this writing, 3.0.2.
  • log4j: We will use the popular open-source logging system to write logs to the console.
  • spring-orm: Provides the ORM (Object relationship management) spring functions.  Basically this provides the link between Spring and Hibernate.
  • commons-dbcp: We’ll use a BasicDataSource from this package to manage the connection pool to the database.  Don’t worry, we only have to declare it, and let Spring and Hibernate do the rest.
  • slf4j-jdk14: Hibernate using the Simple Logging Facade (SLF) interface for logging, so we’ll need this bridge to log4j.
  • mysql-connector-java: We’re using MySQL as our backend database, so we’ll need the driver here.  (Note: if you are not using MySQL, you need to replace this with your database system’s driver)
  • javaassist: JavaAssist is an optimized library for java reflection calls.  It is used by Hibernate to discover structure of Java classes (sort of like looking for getters and setters, but more complicated than that)
  • jstl: The JSP Standard Taglib Library (JSTL) framework, for use with our JSP pages.
  • taglibs-standard: the actual taglibs to put into JSTL.
  • cglib: CGLib is an open-source code generation library, used by both Spring and Hibernate.

20 thoughts on “Spring and Hibernate with Annotations”

  1. Excellent tutorial! Very high quality, it all works beautifully, and very well explained. Thanks for putting it all together. I’ve tried some other similar tutorials before this but none worked. I was using Spring STS as my dev env, and it was fine, with a little change in the initial project setup.

    Only very minor comment is that jsp directory is not usually inside WEB-INF, but alonside it in webapp directory. As I said, this is very minor, viewed against a small mountain of very well designed/executed code.

    All the best
    Noel

    1. Noel,

      Thanks for the kind comments.

      On the matter of the location of the JSP directory, the developers of Spring use the WEB-INF/jsp location themselves (see http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html#mvc-viewresolver ).

      The reason is for security. End users cannot directly reference any file under the WEB-INF directory (with something like http://yoursite.com/webapp/WEB-INF/foo.jsp ) as this produces an error. However, if you use only /jsp, they can reference http://yoursite.com/webapp/jsp/foo.jsp , in the same way they can access http://yoursite.com/webapp/images/logo.gif .

      Using WEB-INF/jsp allows you to maintain complete control of which JSP is shown when, and keeps the script-kiddies from poking around so much.

      Bob

      1. Hi Bob,
        your explanation about why you put the jsp directory into the WEB-INF directory sounds entirely reasonable to me – thanks for that.

        Noel

  2. Wow! Great Tutorial. I’m just in the process of absorbing everything now. The “step by step” code explanation is great for beginners like me. This has got to be the best maven+spring+hibernate tutorial I have come across yet (and I must have seen them all)

    1. Also, it wasn’t working for me at first. I was getting errors like:

      annotations are not supported in -source 1.3
      (use -source 5 or higher to enable annotations)

      I found that Maven’s default java compiler version is 1.3, and even if you don’t have it installed, you’ll still get the above errors unless you explicitly change this by adding the following code within in pom.xml:

      org.apache.maven.plugins
      maven-compiler-plugin
      2.3.2

      1.5
      1.5

        1. Deepak,

          You are 100% correct. You need to specify source and target 1.5 as you have shown above. I have updated the tutorial and source files to reflect this.

          Good catch, thanks!

          Bob

  3. Great tutorial and I learned a lot from this

    I made some changes (Oracle / combined jdbc.properties into the Spring config file etc) and it all works fine

    Then I tried to add some unit tests, but changed the MappedModelDao to implement an interface (extracted through Eclipse) – as explained in
    http://zenoconsulting.wikidot.com/blog:8#toc9

    As soon as I did this, and rebuilt the war, it failed to start in Tomcat with the following exception:

    SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘deletionController’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.technologicaloddity.departments.dao.DepartmentDao com.technologicaloddity.departments.controller.DeletionController.departmentDao; nested exception is java.lang.IllegalArgumentException: Can not set com.technologicaloddity.departments.dao.DepartmentDao field com.technologicaloddity.departments.controller.DeletionController.departmentDao to $Proxy21
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1055)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:511)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:289)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:286)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:188)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:558)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:842)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:416)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:261)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:192)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.technologicaloddity.departments.dao.DepartmentDao com.technologicaloddity.departments.controller.DeletionController.departmentDao; nested exception is java.lang.IllegalArgumentException: Can not set com.technologicaloddity.departments.dao.DepartmentDao field com.technologicaloddity.departments.controller.DeletionController.departmentDao to $Proxy21
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:504)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:280)
    … 21 more
    Caused by: java.lang.IllegalArgumentException: Can not set com.technologicaloddity.departments.dao.DepartmentDao field com.technologicaloddity.departments.controller.DeletionController.departmentDao to $Proxy21
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
    at java.lang.reflect.Field.set(Field.java:657)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:500)
    … 23 more

    Also, I got a similar exception when trying to run a simple JUnit test in Eclipse
    My Spring knowledge is limited, so any help as to what the problem might be would be appreciated
    Thanks

  4. it works with postgres with quite minimal changes, just add the dependency for the jdbc connector for postgres to pom.xml and change jdbc driver class(dispatch-servlet.xml) to postgres(org.postgresql.Driver) and the db url(to something like jdbc:postgresql://localhost:5432/database ).

    great tutorial, better than most other spring and hibernate tutorials on the net! simple working approach that doesn’t need table creation by hand(so simpler to adapt to postgresql).

  5. Hi,

    This is probably one of the best tutorial that I came across.

    Just one thing, why there is no service layer added in the code or shown. Most of the enterprise applications do have a Service Layer for interacting with DB, I guess.

    Thanks & Regards
    Sunil

  6. One more thing, I have to include the servlet dependency in pom file otherwise the project was not getting run and giving error as “Cannot find class file for javax/servlet/ServletContext”.

    Regards
    Sunil

  7. U truly created a number of outstanding stuff within ur article, “Spring and Hibernate with Annotations | Technological
    Oddity”. I may possibly be coming to ur site soon.
    Thanks a lot ,Steve

  8. Now that I’ve just devoted six hours on your website reading your posts, I’m hooked on your blog.
    I bookmarked it as well so that I can keep up with it on a regular basis.
    Have a look at my web site too and tell me what you think.

  9. Heya i am for the first time here. I came across this board and I find It really useful & it helped me out a lot.
    I hope to give something back and aid others like you helped
    me.

  10. This is very interesting, You are a very skilled blogger. I have joined your
    rss feed and look forward to seeking more of your fantastic
    post. Also, I’ve shared your sitee in my social networks!

    1. Lakhan,

      I’m using a MySQL database. The database is automatically created by Hibernate, since “hibernate.hbm2ddl.auto = update” is in the hibernate.properties. So there is no SQL to show. If you have other questions, feel free to ask.

Leave a Reply

Your email address will not be published. Required fields are marked *