Spring and Hibernate with Annotations

Setting Up the Model

Now, let’s get to the fun stuff: Java!  If you remember from the start of this tutorial, we want to have two entities: an Employee and a Department entity.  Each Employee can be a member of any number (even zero) of departments.  Each Department can have any number of Employees.  Let’s look at those entities now.

Employee will provide first and last name, as well as a Set of Departments to which the Employee belongs.  Similarly, Department provides a name and a Set of Employees who are members of the Department.  Both Employee and Department will need an ID field (since they will eventually be in the database).  We’ll provide that ID by extending a simple MappedModel class as seen below.

MappedModels

MappedModel will be our first annotated Java file, so let’s take a look at it.

/src/main/java/com/technologicaloddity/departments/model/MappedModel.java

package com.technologicaloddity.departments.model;

import javax.persistence.*;

import org.hibernate.annotations.*;

@MappedSuperclass
public abstract class MappedModel {

    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy="uuid")
    @Column(name="id")
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

Here’s the line-by-line of MappedModel:

  • Line 1: The Java package name.
  • Line 3: With a few exceptions, we’ll be using the Java Persistence API (JPA) annotations to define entities, so we import it here.  There are two kinds of annotations for entities: JPA and Hibernate-specific annotations.  Although it is good practice to try and use only JPA annotations (since they are the most portable), in practice you will probably need to use a couple of Hibernate-specific ones (and we do in this file)
  • Line 5: MappedModel has two of those Hibernate-specific annotations, so we include the Hibernate annotations package here.  We’ll note which annotations are Hibernate-specific when we get there.
  • Line 7: Hey, here’s a Hibernate-specific mapping now: @MappedSuperclass.  This annotation goes with the class name, and tells Hibernate that even though this specific entity doesn’t have it’s own table (that is, there is no “MappedModel” table in MySQL), you should include the properties that it passes down to subclasses in THEIR tables (specifically, the “id” field should be included in the “employee” and “department” tables, as we shall see in a bit).
  • Line 8: Your common Java class definition.  Notice that MappedModel is abstract, so that it can’t be instantiated (and why would you anyway?)
  • Line 10: @Id is a JPA annotation that tells Hibernate (or other manager) that the field it decorates is the primary key field for this entity.  In this case, the key is the field “id”.
  • Line 11: @GeneratedValue is a JPA annotation that states that the field it decorates (again, field “id”), is automatically generated by the system in some manner.  The “generator” part of the statement tells us how that generation is achieved.   There are many standard types of generators, such as GeneratorType.AUTO, but we will be using a specific system one from Hibernate, so we use the value “system-uuid”.
  • Line 12: @GenericGenerator, the second of our Hibernate-specific annotations, defines what the generator “system-uuid” really is: a UUID generator.  You may wonder why we would use a UUID String ID field instead of, for example, the AUTO type which would use MySQL’s auto number.  To be honest, AUTO would be fine for this application, but in bigger applications, UUID’s have the advantage of being harder to guess, and therefore more difficult to compromise by random parameter testing.
  • Line 13: The @Column JPA annotation tells Hibernate that this field should be stored in a database column with the given name.  Technically, this annotation is not necessary, as JPA/Hibernate will assume that all properties of an Entity (or MappedSuperclass!) will be stored in a column of the same name as the property (“id”, in this case).  We add this here to show the annotation and what it is.  You could, of course, have given the column a name other than the default, such as “myUUID”, and Hibernate would have placed this value in that column instead.
  • Lines 15-22: The definition of the “id” property, along with the normal getter and setter function.  Nothing fancy here, just POJO stuff.
  • Line 23: End of the class definition.

Why do we need MappedModel?  First of all, since every entity is going to need a key field, it saves us time by not having to define the “id” field in every class.  Also, if we ever decide to change how id fields are generated, we only have to change it here.  But even more powerfully, it will save us a lot of coding when we write the Data Access Objects (DAOs).  In fact, the EmployeeDao (which we will see later) only has 3 real lines of code thanks in part to MappedModel!

Now let’s look at the Employee class.

/src/main/java/com/technologicaloddity/departments/model/Employee.java

package com.technologicaloddity.departments.model;

import java.util.*;

import javax.persistence.*;

@Entity
@Table(name="employee")
public class Employee extends MappedModel {

    @Column(name="first_name", length=150, nullable=false)
    private String firstName;

    @Column(name="last_name", length=150, nullable=false)
    private String lastName;

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(
        name="employee_department",
        joinColumns={@JoinColumn(name="employee_id",referencedColumnName="id")},
        inverseJoinColumns={@JoinColumn(name="deparment_id", referencedColumnName="id")}
    )
    private Set<Department> departments;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Set<Department> getDepartments() {
        return departments;
    }

    public void setDepartments(Set<Department> departments) {
        this.departments = departments;
    }    

}

Line-by-line:

  • Line 1: Package definition
  • Lines 3-5: Imports. Notice that for Employee, we only need the JPA annotations, not the Hibernate-specific ones.
  • Line 7: The JPA @Entity annotations tells Hibernate that this is a class that should be managed.. that is, stored in the database.
  • Line 8: The @Table annotation tells Hibernate the name of the table to use for storing this class.  In this case we are using the table named “employee”.
  • Line 9: A standard Java class definition.  Notice that Employee extends MappedModel from above, so it inherits the “id” field.  And since MappedModel has the @MappedSuperclass annotation, “id” will be included in the database (and also act as the key, since it has the @Id annotation in MappedModel).
  • Lines 11-12: Here we define a the “firstName” property of Employee.  As you see, it is decorated with the @Column annotation.  In addition to the name of the field in the database, we have also included a maximum width (150) and told Hibernate that this field may not be null.
  • Lines 13-14: The definition of “lastName” which is exactly like “firstName” above: max 150 width, not null.
  • Lines 17-23: This is the definition of the Departments set, which includes all the Departments to which this Employee belongs.  The details of the Department are not stored in the employee table, of course, but in the department table (which we will define when we reach the Department class).  So how do we link them up?  Since an employee can have 0…n departments, and departments can have 0…n employees, this relationship is Many-To-Many.  In JPA and Hibernate, one side of a Many-To-Many must be the owner of the relationship, and in this case, Employee is the owner (we’ll see the other side of this relationship in the Department class).  So we decorate the Set<Department> with a @ManyToMany annotation to tell Hibernate about the relationship.  (Other types are @OneToOne, @OneToMany, and @ManyToOne).We have also used the @ManyToMany tag to define a fetch strategy.  What’s that?  Basically there are two fetch strategies: eager and lazy.  The default for Hibernate relationships is lazy.  Lazy fetching means that, unless you specifically request it, fetching an Employee from the database will NOT also pull back the Department objects that make up the departments Set.  If you try to access a lazy fetched Set (with, for example, getDepartments()), you will generate an “unable to fetch role of departments; lazy initialization error”.  Eager is the opposite of lazy.  If the link is eager-fetched, Hibernate will always fetch the Department objects that make up the Set<Department> when the Employee is fetched.  This is more database and memory intensive, but it is easier to work with for small projects like this one.In addition to the @ManyToMany annotation, we have also defined a @JoinTable.  The @JoinTable defines the database table where the many-to-many relationship is made.  In this case, we’ve told Hibernate to create a table called “employee_department” that holds the ids of the related Employee and Department object.  The joinColumns property applies to the current class (that is, Employee), whereas the inverseJoinColumns applies to other side of the relationship (that is, Department).
  • Lines 25-47: Your basic getters and setters for the properties of Employee.
  • Line 49: End of the class definition.

Let’s take a look at our final entity, Department.

/src/main/java/com/technologicaloddity/departments/model/Department.java

package com.technologicaloddity.departments.model;

import java.util.*;

import javax.persistence.*;

@Entity
@Table(name="department")
public class Department extends MappedModel {    

    @Column(name="name", length=150, nullable=false, unique=true)
    private String name;

    @ManyToMany(mappedBy="departments",fetch=FetchType.LAZY)
    private Set<Employee> employees;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(Set<Employee> employees) {
        this.employees = employees;
    }

}

Here’s the line-by-line for Department:

  • Line 1: Standard Java package statement.
  • Lines 3-5: Standard imports. Like Employee, we only need the JPA annotations this time.
  • Lines 7-8: Again we use the @Entity annotation to tell JPA that this is a managed entity, and give the @Table name to use for it in MySQL (“department”)
  • Line 9: Like Employee, Department also extends MappedModel, which gives it access to the id field.
  • Lines 11-12: Here we define a property “name”, and give the database @Column specs for it.  Note that we used a new parameter here, “unique”, which does exactly what it says: guarantees that the department’s name is unique in the database.
  • Lines 14-15: Here we see the other side of our @ManyToMany relationship.  We can tell that this side is the “owned” side of the relationship by the “mappedBy” parameter.  Note that the value of mappedBy applies to Employee (the object type that is associated) and not Department itself.  In other words, Department is mapped by Employee.departments.  This time we’ve used the LAZY fetch strategy.  This means that when you retrieve a Department, by default, the related Employees are not retrieved with the Department.  A call to getEmployees() will throw a LazyInitialization exception, since the Employees were not actually loaded.  We’ll see later how to attach the Employee Set to Department when we need it.  Also note that we didn’t have to redefine the @JoinTable, since it is already specified in Employee.
  • Lines 17-31: Common getters and setters.
  • Line 33: End of the class definition.

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 *