This is a first part of the article where we’ll build a RESTful application with Spring, Hibernate and JPA. For this application we’ll also use Maven for build, HSQLDB(in memory mode) as database to persist the data, Jetty as a server and JUnit as a standalone testing tool. In the second part, it will be another article we’ll see how to test a service layer through unit and integration tests.
The goal of the article is to create a RESTful user manager application which will allow create, delete, update, find, getAll or just get a count of users etc.
The Data Access Layer. Generic DAO Pattern
Very often developers forget about beauty of code, about OOP and using code duplication and copy-and-paste wherever it possible. It may cause a daily nightmares and logical contradictions.
DRY-principle(Don’t Repeat Yourself) reduces duplication and very helpful for this situation but it also leads to high coupling and reduced readability. But here we’ll look at slightly different pattern that will help us to save our time and nerves.
DAO pattern provides an architectural foundation, type safety and avoid code duplication. Here you find an
official information about DAO by Oracle.
Let’s see to the Generic Dao structure of the project.
GenericDao interface can be used for a single specified type domain object. A single instance implementing this interface can be used only for the type of domain object specified in the type parameters.
public interface GenericDao<T extends Serializable> {
/**
* Returns the total number of results
*/
public long count();
/**
* Create and save new object in DB.
*/
public T create(T t);
/**
* Remove the entity with the specified type and id from the datastore.
*/
public void delete(Object id);
/**
* Get the entity with the specified type and id from the datastore.
*
* @param id of the entity.
* @return If none is found, return null.
*/
public T find(Object id);
/**
* Get a list of all the objects of the specified type.
*/
public List<T> getAll();
/**
* Update object in DB.
*/
public T update(T t);
}
GenericDaoImpl abstract class is an implementation of generic DAO with Hibernate. This class offers CRUD method for a generic type T. It should be used only through concrete DAO implementations.
Here you can see a Spring @PersistenceContext annotation to inject the entity manager associated with a specific persistence unit. Also an interesting field - Class<T> type, it’s a parametrized type of a class(entity/model) and we use it in EntityManager’s method via reflection.
/**
* Implementation of Generic DAO.
*
* @author Dmitry Nikolaenko
*
* @param <T> The type of the domain object for which this instance is to be used.
*/
public abstract class GenericDaoImpl<T extends Serializable> implements GenericDao<T> {
private static final Logger logger = Logger.getLogger(GenericDaoImpl.class);
// parametrized type of a concrete class
private Class<T> type;
/**
* Represents a JPA connection to the object database, we can uses
* it for CRUD operations (for interacting with the persistence context)
*/
@PersistenceContext
protected EntityManager manager;
@SuppressWarnings("unchecked")
public GenericDaoImpl() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class<T>) pt.getActualTypeArguments()[0];
}
@Override
public long count() {
String entity = type.getSimpleName();
final StringBuilder queryString =
new StringBuilder("select count(ent) from ".concat(entity).concat(" ent"));
// create an instance of Query for executing a Java Persistence query language statement
final Query query = manager.createQuery(queryString.toString());
// execute a SELECT query that returns a single untyped result
return (Long) query.getSingleResult();
}
@Override
public T find(final Object id) {
return manager.find(type, id);
}
@Override
public T create(T t) {
manager.persist(t);
return t;
}
@SuppressWarnings("unchecked")
@Override
public List<T> getAll() {
Query query = manager.createQuery("from ".concat(type.getName()));
return query.getResultList();
}
@Override
public T update(T t) {
return manager.merge(t);
}
@Override
public void delete(Object id) {
manager.remove(manager.getReference(type, id));
}
}
Before we create the next DAO layer we should bind it with some entity.
User class represents a JPA entity which is used by Hibernate and it annotated with JAXB annotations so we can use it via REST. Class
Users is a wrapper for the users class and it also contain JAXB annotations.
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Using Hibernate with Spring, standard JPA annotations work very well.
@Entity - specifies that the class is an entity, we tell Hibernate that this class represent an object that we can persist.
@Table(name = "user") - specifies the primary table for the annotated entity.
@GeneratedValue(strategy = GenerationType.SEQUENCE) - provides for the specification of generation strategies for the values of primary keys.
GenerationType.SEQUENCE - Indicates that the persistence provider must assign primary keys for the entity using a database sequence.
Class
Users is a wrapper for the users class and it also contain JAXB annotations.
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Users {
private List<User> users;
@XmlElement(name = "user")
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
Now we’re ready to use our abstraction DAO layer in concrete DAO implementation. Time to create an entity interface that extend GenericDao and it’s implementation.
UserDao without additional methods but we can add them if needed.
/**
* Interface for specific User entity because we should tell which entity is acceptable.
*
* @author Dmitry Nikolaenko
*
*/
public interface UserDao extends GenericDao<User> {
}
UserDaoImpl extends generic DAO implementation and implement UserDao interface. @Repository annotation indicates that an annotated class is a "Repository", originally defined by Domain-Driven Design as "a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects". Also we can use @Component annotation instead.
/**
* Implementation of Generic DAO.
*
* @author Dmitry Nikolaenko
*/
@Repository
public class UserDaoImpl extends GenericDaoImpl<User> implements UserDao {
}
The Service Layer
/**
* Service for User entity.
*
* @author Dmitry Nikolaenko
*
*/
public interface UserService {
public User create(User user);
public void delete(Integer id);
public User update(User user);
public User find(Integer id);
public List<User> getAll();
public Long count();
}
All of the method are transactional, thanks to the @Transactional annotation. @Autowired marks a method as to be autowired by Spring's dependency injection facilities and we inject a user dao implementation.
/**
* Implementation of the UsersService.
*
* @author Dmitry Nikolaenko
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
@Transactional(readOnly = false)
public User create(User user) {
return userDao.create(user);
}
@Override
@Transactional(readOnly = false)
public void delete(Integer id) {
userDao.delete(id);
}
@Override
@Transactional(readOnly = false)
public User update(User user) {
return userDao.update(user);
}
@Override
@Transactional(readOnly = false)
public User find(Integer id) {
return userDao.find(id);
}
@Override
@Transactional(readOnly = true)
public List<User> getAll() {
return userDao.getAll();
}
@Override
@Transactional(readOnly = true)
public Long count() {
return userDao.count();
}
}
Well, build a
RESTful using Spring Framework.
Configure servlet dispatcher to handle our request in web.xml. And hand this Servlet to handle incoming requests starting with "/rest/*". We use the ContextConfigLocation init parameter to change the location for the main config XML file for the Spring Application Context that is loaded by the DispatcherServlet.
<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>Restful Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-beans.xml</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath*:log4j.properties</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>servlet-context</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servlet-context</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Configure the datasource and persistence unit via Spring and using Hibernate as the JPA provider.
The spring-beans.xml file contains different spring mappings such as transaction manager, entity manager factory bean, data source etc.
-
dataSource bean - java datasource used to connect to contact manager database, we should provide driver class name, username, password etc
-
entityManagerFactory bean - the LocalContainerEntityManagerFactoryBean gives full control over EntityManagerFactory configuration. LocalContainerEntityManagerFactoryBean will create a PersistenceUnitInfo based on the persistence.xml file. This is really great JPA option, allowing for flexible local configuration within the application. It supports links to an existing JDBC DataSource, supports both local and global transactions.
-
transactionManager bean - Transaction manager for EntityManagerFactory
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Configure the JDBC datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Configure the entity manager -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
<property name="persistenceUnitName" value="spring-persistenceUnit" />
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Transaction manager for EntityManagerFactory -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="spring-persistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.dmitrynikol.model.User</class>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
Create a servlet context file
servlet-context.xml.
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- Enabling Spring beans auto-discovery,
scans the classpath of this application for annotation to deploy the bean.
It help us to find class annotated with @Controller,
@Service, @Configuration etc annotation. -->
<context:component-scan base-package="com.dmitrynikol" />
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Enabling Spring MVC configuration through annotations.
Configures the @Controller programming model -->
<mvc:annotation-driven />
</beans>
UserRestService represent a class that will be manipulated by different HTTP methods. The class has been annotated with the @Controller annotation, it means that this is Spring MVC controller able to handling web requests.
@RequestMapping annotation mapping web requests onto our REST class that handles path "/users". All methods has been annotated also with @RequestMapping annotation for handling different requests.
For example, @RequestMapping(method = RequestMethod.POST) will be invoked on the post request. We annotate returning Java object with @ResponseBody annotation which indicates that a method return value should be bound to the web response body.
/**
* Represent a class that will be manipulated by different HTTP methods.
*
* @author Dmitry Nikolaenko
*
*/
@Controller
@RequestMapping("/users")
public class UserRestService {
@Autowired
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Users loadUsers() {
Users users = new Users();
users.setUsers(userService.getAll());
return users;
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseBody
public User updateUser(@PathVariable(value = "id") Integer id, @RequestBody User user) {
return userService.update(user);
}
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public User addUser(@RequestBody User user) {
return userService.create(user);
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteUser(@PathVariable(value = "id") Integer id) {
userService.delete(id);
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public User findUser(@PathVariable(value = "id") Integer id) {
return userService.find(id);
}
}
Here is a link to the
Maven POM file to build the above project.
At this point, we’ve got a final RESTful application, the next thing to do is write a unit and integration test for service layer. But I'll describe this in the next article.
The code for this and the next article is available on
Github.