Maven by Example
7.5. The Simple Persist Module

This module defines two very simple Data Access Objects (DAOs). A DAO
is an object that provides an interface for persistence operations. In
an application that makes use of an Object-Relational Mapping (ORM)
framework such as Hibernate, DAOs are usually defined around
objects. In this project, we are defining two DAO objects:
WeatherDAO and LocationDAO. The WeatherDAO class allows us to
save a Weather object to a database and retrieve a Weather object
by id, and to retrieve Weather objects that match a specific
Location. The LocationDAO has a method that allows us to retrieve
a Location object by zip code. First, let’s take a look at the
simple-persist POM in simple-persist POM.
<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>
<parent>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>simple-persist</artifactId>
<packaging>jar</packaging>
<name>Simple Persistence API</name>
<dependencies>
<dependency>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-model</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.5.ga</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
</project>
This POM file references simple-parent as a parent POM, and it
defines a few dependencies. The dependencies listed in
simple-persist's POM are:
-
org.sonatype.mavenbook.multispring:simple-model:1.0 -
Just like the
simple-weathermodule, this persistence module references the core model objects defined insimple-model. -
org.hibernate:hibernate:3.2.5.ga -
We define a dependency on Hibernate version 3.2.5.ga, but notice
that we’re excluding a dependency of Hibernate. We’re doing this
because the
javax.dependency is not available in the public Maven repository. This dependency happens to be one of those Sun dependencies that has not yet made it into the free central Maven repository. To avoid an annoying message telling us to go download these nonfree dependencies, we simply exclude this dependency from Hibernate.transaction:jta -
javax.servlet:servlet-api:2.4 - Since this project contains a Servlet, we need to include the Servlet API version 2.4.
-
org.springframework:spring:2.0.7 -
This includes the entire Spring Framework as a dependency. It is
generally a good practice to depend on only the components of
Spring you happen to be using. The Spring Framework project has
been nice enough to create focused artifacts such as
spring-hibernate3.
Why depend on Spring? When it comes to Hibernate integration, Spring
allows us to leverage helper classes such as
HibernateDaoSupport. For an example of what is possible with the
help of HibernateDaoSupport, take a look at the code for the
WeatherDAO in simple-persist’s WeatherDAO Class.
simple-persist’s WeatherDAO Class.
package org.sonatype.mavenbook.weather.persist;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.sonatype.mavenbook.weather.model.Location;
import org.sonatype.mavenbook.weather.model.Weather;
public class WeatherDAO extends HibernateDaoSupport { (1)
public WeatherDAO() {}
public void save(Weather weather) { (2)
getHibernateTemplate().save( weather );
}
public Weather load(Integer id) { (3)
return (Weather) getHibernateTemplate().load( Weather.class, id);
}
@SuppressWarnings("unchecked")
public List<Weather> recentForLocation( final Location location ) {
return (List<Weather>) getHibernateTemplate().execute(
new HibernateCallback() { (4)
public Object doInHibernate(Session session) {
Query query = getSession().getNamedQuery("Weather.byLocation");
query.setParameter("location", location);
return new ArrayList<Weather>( query.list() );
}
});
}
}
That’s it. No really, you are done writing a class that can insert new rows, select by primary key, and find all rows in Weather that join to an id in the Location table. Clearly, we can’t stop this book and insert the five hundred pages it would take to get you up to speed on the intricacies of Hibernate, but we can do some very quick explanation:
|
This class extends |
|
|
The |
|
|
The |
|
|
This last method |
Now is a good time for some clarification. HibernateDaoSupport and
HibernateTemplate are classes from the Spring Framework. They were
created by the Spring Framework to make writing Hibernate DAO objects
painless. To support this DAO, we’ll need to do some configuration in
the simple-persist Spring ApplicationContext definition. The XML
document shown in Spring Application Context for simple-persist is stored in
src/main/resources in a file named applicationContext-persist.xml.
Spring Application Context for simple-persist.
<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-2.0.xsd"
default-lazy-init="true">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="annotatedClasses">
<list>
<value>org.sonatype.mavenbook.weather.model.Atmosphere</value>
<value>org.sonatype.mavenbook.weather.model.Condition</value>
<value>org.sonatype.mavenbook.weather.model.Location</value>
<value>org.sonatype.mavenbook.weather.model.Weather</value>
<value>org.sonatype.mavenbook.weather.model.Wind</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</prop>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.connection.pool_size">0</prop>
<prop key="hibernate.connection.driver_class">
org.hsqldb.jdbcDriver
</prop>
<prop key="hibernate.connection.url">
jdbc:hsqldb:data/weather;shutdown=true
</prop>
<prop key="hibernate.connection.username">sa</prop>
<prop key="hibernate.connection.password"></prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
</props>
</property>
</bean>
<bean id="locationDAO"
class="org.sonatype.mavenbook.weather.persist.LocationDAO">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="weatherDAO"
class="org.sonatype.mavenbook.weather.persist.WeatherDAO">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
In this application context, we’re accomplishing a few things. The
sessionFactory bean is the bean from which the DAOs retrieve
Hibernate Session objects. This bean is an instance of
AnnotationSessionFactoryBean and is supplied with a list of
annotatedClasses. Note that the list of annotated classes is the
list of classes defined in our simple-model module. Next, the
sessionFactory is configured with a set of Hibernate configuration
properties (hibernateProperties). In this example, our Hibernate
properties define a number of settings:
-
hibernate.dialect -
This setting controls how SQL is to be generated for our
database. Since we are using the HSQLDB database, our database
dialect is set to
org.+HSQLDialect+. Hibernate has dialects for all major databases such as Oracle, MySQL, Postgres, and SQL Server.hibernate.dialect. -
hibernate.connection.* - In this example, we’re configuring the JDBC connection properties from the Spring configuration. Our applications are configured to run against a HSQLDB in the ./data/weather directory. In a real enterprise application, it is more likely you would use something like JNDI to externalize database configuration from your application’s code.
Lastly, in this bean definition file, both of the simple-persist DAO
objects are created and given a reference to the sessionFactory bean
just defined. Just like the Spring application context in
simple-weather, this applicationContext-persist.xml file defines
the architecture of a submodule in a larger enterprise design. If you
were working with a larger collection of persistence classes, you
might find it useful to capture them in an application context which
is separate from your application.
There’s one last piece of the puzzle in simple-persist. Later in
this chapter, we’re going to hibernate.cfg.xml in
src/main/resources. The purpose of this file (which duplicates some
of the configuration in applicationContext-persist.xml) is to allow
us to leverage the Maven Hibernate3 plugin to generate Data Definition
Language (DDL) from nothing more than our annotations. See
simple-persist hibernate.cfg.xml.
simple-persist hibernate.cfg.xml.
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:data/weather</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="connection.shutdown">true</property>
<!-- JDBC connection pool (use the built-in one) -->
<property name="connection.pool_size">1</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- disable batching so HSQLDB will propagate errors correctly. -->
<property name="jdbc.batch_size">0</property>
<!-- List all the mapping documents we're using -->
<mapping class="org.sonatype.mavenbook.weather.model.Atmosphere"/>
<mapping class="org.sonatype.mavenbook.weather.model.Condition"/>
<mapping class="org.sonatype.mavenbook.weather.model.Location"/>
<mapping class="org.sonatype.mavenbook.weather.model.Weather"/>
<mapping class="org.sonatype.mavenbook.weather.model.Wind"/>
</session-factory>
</hibernate-configuration>
The contents of Spring Application Context for simple-persist and
simple-parent Project POM are redundant. While the Spring
Application Context XML is going to be used by the web application and
the command-line application, the hibernate.cfg.xml exists only to
support the Maven Hibernate3 plugin. Later in this chapter, we’ll see
how to use this hibernate.cfg.xml and the Maven Hibernate3 plugin to
generate a database schema based on the annotated object model defined
in simple-model. This hibernate.cfg.xml file is the file that will
configure the JDBC connection properties and enumerate the list of
annotated model classes for the Maven Hibernate3 plugin.
