7.3. The Simple Model Module
The first thing most enterprise projects need is an object model. An
object model captures the core set of domain objects in any system. A
banking system might have an object model which consists of
Account, Customer, and Transaction objects, or a system to
capture and communicate sports scores might have a Team and a Game
object. Whatever it is, there’s a good chance that you’ve modeled the
concepts in your system in an object model. It is a common practice in
Maven projects to separate this project into a separate project which
is widely referenced. In this system we are capturing each query to
the Yahoo Weather feed with a Weather object which references four
other objects. Wind direction, chill, and speed are stored in a Wind
object. Location data including the zip code, city, region, and
country are stored in a Location class. Atmospheric conditions such
as the humidity, maximum visibility, barometric pressure, and whether
the pressure is rising or falling are stored in an Atmosphere
class. A textual description of conditions, the temperature, and the
date of the observation is stored in a Condition class.
The pom.xml file for this simple object model contains one
dependency that bears some explanation. Our object model is annotated
with Hibernate Annotations. We use these annotations to map the model
objects in this model to tables in a relational database. The
dependency is org.hibernate:hibernate-annotations:3.3.0.ga. Take a
look at the pom.xml shown in simple-model pom.xml, and
then look at the next few examples for some illustrations of these
annotations.
simple-model pom.xml.
<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-model</artifactId>
<packaging>jar</packaging>
<name>Simple Object Model</name>
<dependencies>
<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>
</dependencies>
</project>
In src/main/java/org/sonatype/mavenbook/weather/model, we have
Weather.java, which contains the annotated Weather model
object. The Weather object is a simple Java bean. This means that we
have private member variables like id, location, condition,
wind, atmosphere, and date exposed with public getter and setter
methods that adhere to the following pattern: if a property is named
name, there will be a public no-arg getter method named getName(),
and there will be a one-argument setter named setName(String name).
Although we show the
getter and setter methods for the id property, we’ve omitted most of
the getters and setters for most of the other properties to save a few
trees. See Annotated Weather Model Object.
Annotated Weather Model Object.
package org.sonatype.mavenbook.weather.model;
import javax.persistence.*;
import java.util.Date;
@Entity
@NamedQueries({
@NamedQuery(name="Weather.byLocation",
query="from Weather w where w.location = :location")
})
public class Weather {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@ManyToOne(cascade=CascadeType.ALL)
private Location location;
@OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
private Condition condition;
@OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
private Wind wind;
@OneToOne(mappedBy="weather",cascade=CascadeType.ALL)
private Atmosphere atmosphere;
private Date date;
public Weather() {}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
// All getter and setter methods omitted...
}
In the Weather class, we are using Hibernate annotations to provide
guidance to the simple-persist project. These annotations are used
by Hibernate to map an object to a table in a relational
database. Although a full explanation of Hibernate annotations is
beyond the scope of this chapter, here is a brief explanation for the
curious. The @Entity annotation marks this class as a persistent
entity. We’ve omitted the @Table annotation on this class, so
Hibernate is going to use the name of the class as the name of the
table to map Weather to. The @NamedQueries annotation defines a
query that is used by the WeatherDAO in simple-persist. The query
language in the @NamedQuery annotation is written in something
called Hibernate Query Language (HQL). Each member variable is
annotated with annotations that define the type of column and any
relationships implied by that column:
-
Id
-
The
id property is annotated with @Id. This marks the id
property as the property that contains the primary key in a
database table. The @GeneratedValue controls how new primary key
values are generated. In the case of id, we’re using the
IDENTITY GenerationType, which will use the underlying
database’s identity generation facilities.
-
Location
-
Each
Weather object instance corresponds to a Location
object. A Location object represents a zip code, and the
@ManyToOne makes sure that Weather objects that point to the
same Location object reference the same instance. The cascade
attribute of the @ManyToOne makes sure that we persist a
Location object every time we persist a Weather object.
-
Condition, Wind, Atmosphere
-
Each of these objects is mapped as a
@OneToOne with the
CascadeType of ALL. This means that every time we save a
Weather object, we’ll be inserting a row into the Weather
table, the Condition table, the Wind table, and the
Atmosphere table.
-
Date
-
Date is not annotated. This means that Hibernate is going to use
all of the column defaults to define this mapping. The column name
is going to be date, and the column type is going to be the
appropriate time to match the Date object.
Note
If you have a property you wish to omit from a table mapping,
you would annotate that property with @Transient.
Next, take a look at one of the secondary model objects, Condition,
shown in simple-model’s Condition Model Object.. This class also resides
in src/main/java/org/sonatype/mavenbook/weather/model.
simple-model’s Condition Model Object.
package org.sonatype.mavenbook.weather.model;
import javax.persistence.*;
@Entity
public class Condition {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String text;
private String code;
private String temp;
private String date;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="weather_id", nullable=false)
private Weather weather;
public Condition() {}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
// All getter and setter methods omitted...
}
The Condition class resembles the Weather class. It is annotated
as an @Entity, and it has similar annotations on the id
property. The text, code, temp, and date properties are all
left with the default column settings, and the weather property is
annotated with a @OneToOne annotation and another annotation that
references the associated Weather object with a foreign key column
named weather_id.