To understand the behaviour of various Java language-level objects with respect to the persistence service, we need to classify them into two groups:
An entity exists independently of any other objects holding references to the entity. Contrast this with the usual Java model where an unreferenced object is garbage collected. Entities must be explicitly saved and deleted (except that saves and deletions may be cascaded from a parent entity to its children). This is different from the ODMG model of object persistence by reachablity - and corresponds more closely to how application objects are usually used in large systems. Entities support circular and shared references. They may also be versioned.
An entity's persistent state consists of references to other entities and instances of value types. Values are primitives, collections (not what's inside a collection), components and certain immutable objects. Unlike entities, values (in particular collections and components) are persisted and deleted by reachability. Since value objects (and primitives) are persisted and deleted along with their containing entity they may not be independently versioned. Values have no independent identity, so they cannot be shared by two entities or collections.
Up until now, we've been using the term "persistent class" to refer to
entities. We will continue to do that. Strictly speaking, however, not all
user-defined classes with persistent state are entities. A
component is a user defined class with value semantics.
A Java property of type java.lang.String
also has value
semantics. Given this definition, we can say that all types (classes) provided
by the JDK have value type semantics in Java, while user-defined types may
be mapped with entity or value type semantics. This decision is up to the
application developer. A good hint for an entity class in a domain model are
shared references to a single instance of that class, while composition or
aggregation usually translates to a value type.
We'll revisit both concepts throughout the documentation.
The challenge is to map the Java type system (and the developers' definition of
entities and value types) to the SQL/database type system. The bridge between
both systems is provided by Hibernate: for entities we use
<class>
, <subclass>
and so on.
For value types we use <property>
,
<component>
, etc, usually with a type
attribute. The value of this attribute is the name of a Hibernate
mapping type. Hibernate provides many mappings (for standard
JDK value types) out of the box. You can write your own mapping types and implement your
custom conversion strategies as well, as you'll see later.
All built-in Hibernate types except collections support null semantics.
The built-in basic mapping types may be roughly categorized into
integer, long, short, float, double, character, byte,
boolean, yes_no, true_false
Type mappings from Java primitives or wrapper classes to appropriate
(vendor-specific) SQL column types. boolean, yes_no
and true_false
are all alternative encodings for
a Java boolean
or java.lang.Boolean
.
string
A type mapping from java.lang.String
to
VARCHAR
(or Oracle VARCHAR2
).
date, time, timestamp
Type mappings from java.util.Date
and its subclasses
to SQL types DATE
, TIME
and
TIMESTAMP
(or equivalent).
calendar, calendar_date
Type mappings from java.util.Calendar
to
SQL types TIMESTAMP
and DATE
(or equivalent).
big_decimal, big_integer
Type mappings from java.math.BigDecimal
and
java.math.BigInteger
to NUMERIC
(or Oracle NUMBER
).
locale, timezone, currency
Type mappings from java.util.Locale
,
java.util.TimeZone
and
java.util.Currency
to VARCHAR
(or Oracle VARCHAR2
).
Instances of Locale
and Currency
are
mapped to their ISO codes. Instances of TimeZone
are
mapped to their ID
.
class
A type mapping from java.lang.Class
to
VARCHAR
(or Oracle VARCHAR2
).
A Class
is mapped to its fully qualified name.
binary
Maps byte arrays to an appropriate SQL binary type.
text
Maps long Java strings to a SQL CLOB
or
TEXT
type.
serializable
Maps serializable Java types to an appropriate SQL binary type. You
may also indicate the Hibernate type serializable
with
the name of a serializable Java class or interface that does not default
to a basic type.
clob, blob
Type mappings for the JDBC classes java.sql.Clob
and
java.sql.Blob
. These types may be inconvenient for some
applications, since the blob or clob object may not be reused outside of
a transaction. (Furthermore, driver support is patchy and inconsistent.)
imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
imm_serializable, imm_binary
Type mappings for what are usually considered mutable Java types, where
Hibernate makes certain optimizations appropriate only for immutable
Java types, and the application treats the object as immutable. For
example, you should not call Date.setTime()
for an
instance mapped as imm_timestamp
. To change the
value of the property, and have that change made persistent, the
application must assign a new (nonidentical) object to the property.
Unique identifiers of entities and collections may be of any basic type except
binary
, blob
and clob
.
(Composite identifiers are also allowed, see below.)
The basic value types have corresponding Type
constants defined on
org.hibernate.Hibernate
. For example, Hibernate.STRING
represents the string
type.
It is relatively easy for developers to create their own value types. For example,
you might want to persist properties of type java.lang.BigInteger
to VARCHAR
columns. Hibernate does not provide a built-in type
for this. But custom types are not limited to mapping a property (or collection element)
to a single table column. So, for example, you might have a Java property
getName()
/setName()
of type
java.lang.String
that is persisted to the columns
FIRST_NAME
, INITIAL
, SURNAME
.
To implement a custom type, implement either org.hibernate.UserType
or org.hibernate.CompositeUserType
and declare properties using the
fully qualified classname of the type. Check out
org.hibernate.test.DoubleStringType
to see the kind of things that
are possible.
<property name="twoStrings" type="org.hibernate.test.DoubleStringType"> <column name="first_string"/> <column name="second_string"/> </property>
Notice the use of <column>
tags to map a property to multiple
columns.
The CompositeUserType
, EnhancedUserType
,
UserCollectionType
, and UserVersionType
interfaces provide support for more specialized uses.
You may even supply parameters to a UserType
in the mapping file. To
do this, your UserType
must implement the
org.hibernate.usertype.ParameterizedType
interface. To supply parameters
to your custom type, you can use the <type>
element in your mapping
files.
<property name="priority"> <type name="com.mycompany.usertypes.DefaultValueIntegerType"> <param name="default">0</param> </type> </property>
The UserType
can now retrieve the value for the parameter named
default
from the Properties
object passed to it.
If you use a certain UserType
very often, it may be useful to define a
shorter name for it. You can do this using the <typedef>
element.
Typedefs assign a name to a custom type, and may also contain a list of default
parameter values if the type is parameterized.
<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero"> <param name="default">0</param> </typedef>
<property name="priority" type="default_zero"/>
It is also possible to override the parameters supplied in a typedef on a case-by-case basis by using type parameters on the property mapping.
Even though Hibernate's rich range of built-in types and support for components means you
will very rarely need to use a custom type, it is nevertheless
considered good form to use custom types for (non-entity) classes that occur frequently
in your application. For example, a MonetaryAmount
class is a good
candidate for a CompositeUserType
, even though it could easily be mapped
as a component. One motivation for this is abstraction. With a custom type, your mapping
documents would be future-proofed against possible changes in your way of representing
monetary values.