Michal Vrtiak

About Michal Vrtiak

Michal is a freelancer currently located in Prague, Czech Republic with huge passion for Java platform. He is very enthusiastic about Dependency Injection, IntelliJ IDEA and loves to use both Spring and Java EE.

Spring – Persistence layer – writing entities and configuring Hibernate

Welcome to the second part of this tutorial. Don’t freak out when you see how long this article is – I promise you it’s mostly easy POJOs and some generated code.

Before we start, we need to update our Maven dependencies, because we will be using Hibernate and Spring now. Add following dependencies to your pom.xml:

  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>3.6.8.Final</version>
  </dependency>
                <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.6</version>
  </dependency>
  
  <!-- spring framework -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
                <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
                <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>

If you’re new to Maven you might be wondering now – how do you know these? Where can I get them? Well, just go to http://mvnrepository.com/ and type what your ale looking for. You will get complete code for maven dependencies. If you have ever tried to assemble Spring or Hibernate application yourself without using Maven, you probably know how painful it was. With Maven things are so much easier.

Also note, that we have included dependency to MySQL’s connector. If you’ve decided to use other database, don’t forget to change this.

With Hibernate we have 2 options how to turn our POJOs to entites. Either we use XML and create mapping files, or we will put some meta information to our code (java annotations). Some people are afraid of those and consider this as coupling with framework. It is true that you will need javax.persistence annotations at your classpath, but we won’t be implementing interfaces or extending framework classes. We will just add some meta information to our code and POJOs will still be simply POJOs with some extra information.

We will turn our POJOs to entities now. We will need to do following changes:

  • Add default no-args constructor for Hibernate
  • Create getters and setters for fields
  • add equals and hashCode methods.
  • Add persistence annotations. Note that we also use @Table annotation to distinguish between Java and SQL naming conventions.
  • Add id fields. These will be primary keys in our relational database.

This is quite lot of boilerplate code, so let your IDE help you. Most modern IDEs will generate construcors, getters, setters, equals and hashCode for you.

package org.timesheet.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = 'employee')
public class Employee {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;
 private String name;
 private String department;
 
 public Employee() {
 }

 public Employee(String name, String department) {
  this.name = name;
  this.department = department;
 }
 
 public String getName() {
  return name;
 }
 
 public String getDepartment() {
  return department;
 }
 
 public Long getId() {
  return id;
 }
 
 public void setId(Long id) {
  this.id = id;
 }

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

 public void setDepartment(String department) {
  this.department = department;
 }

 @Override
 public String toString() {
  return 'Employee [id=' + id + ', name=' + name + ', department='
    + department + ']';
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result
    + ((department == null) ? 0 : department.hashCode());
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  result = prime * result + ((name == null) ? 0 : name.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj) {
   return true;
  }
  if (obj == null) {
   return false;
  }
  if (!(obj instanceof Employee)) {
   return false;
  }
  Employee other = (Employee) obj;
  if (department == null) {
   if (other.department != null) {
    return false;
   }
  } else if (!department.equals(other.department)) {
   return false;
  }
  if (id == null) {
   if (other.id != null) {
    return false;
   }
  } else if (!id.equals(other.id)) {
   return false;
  }
  if (name == null) {
   if (other.name != null) {
    return false;
   }
  } else if (!name.equals(other.name)) {
   return false;
  }
  return true;
 }
 
}
package org.timesheet.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = 'manager')
public class Manager {
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;
 private String name;
 
 public Manager() {
 }

 public Manager(String name) {
  this.name = name;
 }
 
 public String getName() {
  return name;
 }

 public Long getId() {
  return id;
 }

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

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

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  result = prime * result + ((name == null) ? 0 : name.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj) {
   return true;
  }
  if (obj == null) {
   return false;
  }
  if (!(obj instanceof Manager)) {
   return false;
  }
  Manager other = (Manager) obj;
  if (id == null) {
   if (other.id != null) {
    return false;
   }
  } else if (!id.equals(other.id)) {
   return false;
  }
  if (name == null) {
   if (other.name != null) {
    return false;
   }
  } else if (!name.equals(other.name)) {
   return false;
  }
  return true;
 }

 @Override
 public String toString() {
  return 'Manager [id=' + id + ', name=' + name + ']';
 }
 
}
package org.timesheet.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name='timesheet')
public class Timesheet {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;
 
 @OneToOne
 @JoinColumn(name = 'employee_id')
 private Employee who;
 
 @OneToOne
 @JoinColumn(name = 'task_id')
 private Task task;
 private Integer hours;
 
 public Timesheet() {
 }
 
 public Timesheet(Employee who, Task task, Integer hours) {
  this.who = who;
  this.task = task;
  this.hours = hours;
 }

 public Employee getWho() {
  return who;
 }

 public Task getTask() {
  return task;
 }
 
 public Integer getHours() {
  return hours;
 }
 
 public Long getId() {
  return id;
 }

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

 public void setWho(Employee who) {
  this.who = who;
 }

 public void setTask(Task task) {
  this.task = task;
 }

 public void setHours(Integer hours) {
  this.hours = hours;
 }

 /**
  * Manager can alter hours before closing task
  * @param hours New amount of hours
  */
 public void alterHours(Integer hours) {
  this.hours = hours;
 }

 @Override
 public String toString() {
  return 'Timesheet [id=' + id + ', who=' + who + ', task=' + task
    + ', hours=' + hours + ']';
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((hours == null) ? 0 : hours.hashCode());
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  result = prime * result + ((task == null) ? 0 : task.hashCode());
  result = prime * result + ((who == null) ? 0 : who.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj) {
   return true;
  }
  if (obj == null) {
   return false;
  }
  if (!(obj instanceof Timesheet)) {
   return false;
  }
  Timesheet other = (Timesheet) obj;
  if (hours == null) {
   if (other.hours != null) {
    return false;
   }
  } else if (!hours.equals(other.hours)) {
   return false;
  }
  if (id == null) {
   if (other.id != null) {
    return false;
   }
  } else if (!id.equals(other.id)) {
   return false;
  }
  if (task == null) {
   if (other.task != null) {
    return false;
   }
  } else if (!task.equals(other.task)) {
   return false;
  }
  if (who == null) {
   if (other.who != null) {
    return false;
   }
  } else if (!who.equals(other.who)) {
   return false;
  }
  return true;
 }
}

And finally, here’s Task entity when we needed to use also @ManyToMany mapping. That’s because one employee can work on multiple tasks and one task can have assigned multiple employees. We’ve defined how our m:n will look like, using @JoinTable and @JoinColumn annotations.

package org.timesheet.domain;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Entity
@Table(name = 'task')
public class Task {

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

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = 'task_employee',
            joinColumns = {@JoinColumn(name = 'task_id')},
            inverseJoinColumns = {@JoinColumn(name = 'employee_id')}
    )
    private List<Employee> assignedEmployees = new ArrayList<Employee>();

    @OneToOne
    @JoinColumn(name = 'manager_id')
    private Manager manager;

    private String description;
    boolean completed;

    public Task() {
    }

    public Task(String description, Manager manager, Employee... employees) {
        this.description = description;
        this.manager = manager;
        assignedEmployees.addAll(Arrays.asList(employees));
        completed = false;
    }

    public Manager getManager() {
        return manager;
    }

    public List<Employee> getAssignedEmployees() {
        return assignedEmployees;
    }

    public void addEmployee(Employee e) {
        assignedEmployees.add(e);
    }

    public void removeEmployee(Employee e) {
        assignedEmployees.remove(e);
    }

    public Long getId() {
        return id;
    }

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

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }

    public void setAssignedEmployees(List<Employee> assignedEmployees) {
        this.assignedEmployees = assignedEmployees;
    }

    public void setManager(Manager manager) {
        this.manager = manager;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Task task = (Task) o;

        if (completed != task.completed) {
            return false;
        }
        if (description != null ? !description.equals(task.description) : task.description != null) {
            return false;
        }
        if (id != null ? !id.equals(task.id) : task.id != null) {
            return false;
        }
        if (manager != null ? !manager.equals(task.manager) : task.manager != null) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result = id != null ? id.hashCode() : 0;
        result = 31 * result + (manager != null ? manager.hashCode() : 0);
        result = 31 * result + (description != null ? description.hashCode() : 0);
        result = 31 * result + (completed ? 1 : 0);
        return result;
    }

    @Override
    public String toString() {
        return 'Task{' +
                'id=' + id +
                ', assignedEmployees=' + assignedEmployees +
                ', manager=' + manager +
                ', description='' + description + '\'' +
                ', completed=' + completed +
                '}';
    }
}

So we didn’t really do anything special to model. If you fancy some UML look at the following picture, relations are same as before.

Okay we have entites, now let’s create database. Pick some tool for database management (even plain terminal is fine) and create timesheet database like so (by default mysql will install to /usr/local/mysql/bin/mysql at Mac OS X):

$ mysql -u root
mysql > create database timesheet;

If you’ve ever configured Hibernate before you probably know, that you need quite many files and boilerplate code when dealing for example with SessionFactory. These things are much simpler with Spring.

We will now create our first Spring Bean Configuration File – it’s file where we register beans for Spring container. If I had to explain what’s this file to someone who doesn’t know what Spring is at all – it’s kind of magic bag where Spring container can find objects.

Modern IDEs will help you get all the XML namespaces right, for example you can see pictures from STS wizard. NetBeans has something similar and IntelliJ resolves namespaces on the fly.

Name configuration file persistence-beans.xml and we will put it under src/main/resources folder.

So setting up Hibernate, transactions, annotation config and so on is as simple as creating few beans in XML file. Alternatively, we can use Java Config for Spring, but XML configs are still used much more, so we’ll stick to those. I don’t want to discourage you from using Java Config though! XML config is much much more popular at this moment, but I can’t guarantee that for the next few years.
I’ve commented every bean to make sure you understand what we did there before proceeding. If you want to get some visual grasp of connections between beans you can again use some tooling – in STS it’s called Bean Graph, in IntelliJ it’s Dependencies. You can see sample of dependencies on the picture below.

<?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.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-3.1.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-3.1.xsd'>

 <!-- we can use annotations -->
 <context:annotation-config />  
 
 <!-- package to look for annotated classes -->
 <context:component-scan base-package='org.timesheet.service.impl' />
 
 <!-- we will manage transactions with annotations -->
 <tx:annotation-driven />

 <!-- data source for our database -->
 <bean id='dataSource' 
  class='org.springframework.jdbc.datasource.DriverManagerDataSource'>
  <property name='driverClassName' 
   value='com.mysql.jdbc.jdbc2.optional.MysqlDataSource' />
  <property name='url' value='jdbc:mysql://localhost/timesheet' />
  <property name='username' value='root' />
  <property name='password' value='' />
 </bean>
 
 <!-- configure hibernate session factory -->
 <bean id='sessionFactory'
  class='org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean'>
  <property name='dataSource' ref='dataSource' />
  <property name='annotatedClasses' >
   <list>
    <value>org.timesheet.domain.Employee</value>
    <value>org.timesheet.domain.Manager</value>
    <value>org.timesheet.domain.Task</value>
    <value>org.timesheet.domain.Timesheet</value>
   </list>
  </property>
  <property name='hibernateProperties'>
   <props>
    <prop key='dialect'>org.hibernate.dialect.MySQL5InnoDBDialect</prop>
    <prop key='hibernate.show_sql'>true</prop>
    <prop key='hibernate.hbm2ddl.auto'>update</prop>
   </props>
  </property> 
 </bean>
 
</beans>

Okay, that was quite lot of configuration, he? What’s not so good is that we’ve placed names of our entities to XML as plain text, so it isn’t refactoring friendly. But I think for this tutorial it’s acceptable :) Let’s write integration test for Hibernate so we know that everything is set up properly.

package org.timesheet.integration;

import static org.junit.Assert.*;

import org.hibernate.SessionFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

@ContextConfiguration(locations = '/persistence-beans.xml')
public class HibernateConfigurationTest extends AbstractJUnit4SpringContextTests {
 
 @Autowired
 private SessionFactory sessionFactory;

 @Test
 public void testHibernateConfiguration() {
  // Spring IOC container instantiated and prepared sessionFactory
  assertNotNull (sessionFactory); 
 }

}

I want you to note 2 things here. First, we extend AbstractJUnit4SpringContextTests class. We tell it where it should look for actual XML config with spring beans. Otherwise we would have to create Spring container by ourselves, which means more boilerplate code.

Second, we use @Autowired annotation. That means we don’t create instance of SessionFactory by hand using new operator, but we will have it Autowired (Injected) by Spring container! That’s one of the most important purposes of Spring container – depend on interfaces and have implementations injected instead of creating them by hand.
Everything should work now and I think that’s enough for this part.

If you like you can check plain SQL, and see tables are here, do it like so:

mysql> use timesheet;
mysql> show tables;
+---------------------+
| Tables_in_timesheet |
+---------------------+
| employee            |
| manager             |
| task                |
| task_employee       |
| timesheet           |
+---------------------+
5 rows in set (0.00 sec)

Reference: Part 2 – Persistence layer – writing entities and configuring Hibernate from our JCG partner Michal Vrtiak at the vrtoonjava blog.

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

3 Responses to "Spring – Persistence layer – writing entities and configuring Hibernate"

  1. Eran says:

    Can you please post a link to part 1 of this tutorial

    “Welcome to the second part of this tutorial …”

    10x

    • Hello Eran, you can find all parts of the tutorial at our archive section down at the bottom of our site. We usually post all the parts of a multi-part tutorial at once so you can find them at the archived tree grouped together.

      BRs

  2. Oleksiy Rezchykov says:

    Hello Nikos, just two short comments. You have used Fetch.EAGER with @ManyToMany. I think this shouldn’t be done unless it is really needed. I think this could be explained in more details, especially for beginners. My second point is about extending AbstractJUnit4SpringContextTests. Why can’t you use @RunWith annotation for the same purpose?

Leave a Reply


two × 4 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books