Author: steve.ebersole(a)jboss.com
Date: 2010-05-25 15:07:43 -0400 (Tue, 25 May 2010)
New Revision: 19607
Added:
core/trunk/documentation/manual/src/main/docbook/en-US/content/type.xml
Log:
Added: core/trunk/documentation/manual/src/main/docbook/en-US/content/type.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/type.xml
(rev 0)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/type.xml 2010-05-25
19:07:43 UTC (rev 19607)
@@ -0,0 +1,990 @@
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Inc.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="types">
+ <title>Types</title>
+
+ <para>
+ As an Object/Relational Mapping solution, Hibernate deals with both the Java and
JDBC representations of
+ application data. An online catalog application, for example, most likely has
<classname>Product</classname>
+ object with a number of attributes such as a <literal>sku</literal>,
<literal>name</literal>, etc. For these
+ individual attributes, Hibernate must be able to read the values out of the
database and write them back. This
+ 'marshalling' is the function of a <emphasis>Hibernate
type</emphasis>, which is an implementation of the
+ <interfacename>org.hibernate.type.Type</interfacename> interface. In
addition, a
+ <emphasis>Hibernate type</emphasis> describes various aspects of
behavior of the Java type such as "how is
+ equality checked?" or "how are values cloned?".
+ </para>
+
+ <important>
+ <para>
+ A Hibernate type is neither a Java type nor a SQL datatype; it provides a
information about both.
+ </para>
+ <para>
+ When you encounter the term <emphasis>type</emphasis> in regards
to Hibernate be aware that usage might
+ refer to the Java type, the SQL/JDBC type or the Hibernate type.
+ </para>
+ </important>
+
+ <para>
+ Hibernate categorizes types into two high-level groups: value types (see <xref
linkend="types.value"/>) and
+ entity types (see <xref linkend="types.entity"/>).
+ </para>
+
+ <section id="types.value">
+ <title>Value types</title>
+
+ <para>
+ The main distinguishing characteristic of a value type is the fact that they
do not define their own
+ lifecycle. We say that they are "owned" by something else
(specifically an entity, as we will see later)
+ which defines their lifecycle. Value types are further classified into 3
sub-categories: basic types (see
+ <xref linkend="types.value.basic"/>), composite types (see
<xref linkend="types.value.composite"/>)
+ amd collection types (see <xref
linkend="types.value.collection"/>).
+ </para>
+
+ <section id="types.value.basic">
+ <title>Basic value types</title>
+ <para>
+ The norm for basic value types is that they map a single database value
(column) to a single,
+ non-aggregated Java type. Hibernate provides a number of built-in basic
types, which we will present
+ in the following sections by the Java type. Mainly these follow the
natural mappings recommended in the
+ JDBC specification. We will later cover how to override these mapping
and how to provide and use
+ alternative type mappings.
+ </para>
+ <section id="types.value.basic.string">
+ <title>java.lang.String</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.StringType</classname></term>
+ <listitem>
+ <para>
+ Maps a string to the JDBC VARCHAR type. This is the
standard mapping for a string if
+ no Hibernate type is specified.
+ </para>
+ <para>
+ Registered under <literal>string</literal>
and <literal>java.lang.String</literal>
+ in the type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.MaterializedClob</classname></term>
+ <listitem>
+ <para>
+ Maps a string to a JDBC CLOB type
+ </para>
+ <para>
+ Registered under
<literal>materialized_clob</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.TextType</classname></term>
+ <listitem>
+ <para>
+ Maps a string to a JDBC LONGVARCHAR type
+ </para>
+ <para>
+ Registered under <literal>text</literal> in
the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.character">
+ <title><classname>java.lang.Character</classname> (or
char primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CharacterType</classname></term>
+ <listitem>
+ <para>
+ Maps a char or
<classname>java.lang.Character</classname> to a JDBC CHAR
+ </para>
+ <para>
+ Registered under <literal>char</literal> and
<literal>java.lang.Character</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.value.basic.boolean">
+ <title><classname>java.lang.Boolean</classname> (or
boolean primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BooleanType</classname></term>
+ <listitem>
+ <para>
+ Maps a boolean to a JDBC BIT type
+ </para>
+ <para>
+ Registered under <literal>boolean</literal>
and <literal>java.lang.Boolean</literal> in
+ the type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.NumericBooleanType</classname></term>
+ <listitem>
+ <para>
+ Maps a boolean to a JDBC INTEGER type as 0 = false, 1 =
true
+ </para>
+ <para>
+ Registered under
<literal>numeric_boolean</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.YesNoType</classname></term>
+ <listitem>
+ <para>
+ Maps a boolean to a JDBC CHAR type as ('N' |
'n') = false, ( 'Y' | 'y' ) = true
+ </para>
+ <para>
+ Registered under <literal>yes_no</literal> in
the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.TrueFalseType</classname></term>
+ <listitem>
+ <para>
+ Maps a boolean to a JDBC CHAR type as ('F' |
'f') = false, ( 'T' | 't' ) = true
+ </para>
+ <para>
+ Registered under
<literal>true_false</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.byte">
+ <title><classname>java.lang.Byte</classname> (or byte
primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.ByteType</classname></term>
+ <listitem>
+ <para>
+ Maps a byte or
<classname>java.lang.Byte</classname> to a JDBC TINYINT
+ </para>
+ <para>
+ Registered under <literal>byte</literal> and
<literal>java.lang.Byte</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.short">
+ <title><classname>java.lang.Short</classname> (or short
primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.ShortType</classname></term>
+ <listitem>
+ <para>
+ Maps a short or
<classname>java.lang.Short</classname> to a JDBC SMALLINT
+ </para>
+ <para>
+ Registered under <literal>short</literal> and
<literal>java.lang.Short</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.int">
+ <title><classname>java.lang.Integer</classname> (or int
primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.IntegerTypes</classname></term>
+ <listitem>
+ <para>
+ Maps an int or
<classname>java.lang.Integer</classname> to a JDBC INTEGER
+ </para>
+ <para>
+ Registered under <literal>int</literal> and
<literal>java.lang.Integer</literal>in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.long">
+ <title><classname>java.lang.Long</classname> (or long
primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.LongType</classname></term>
+ <listitem>
+ <para>
+ Maps a long or
<classname>java.lang.Long</classname> to a JDBC BIGINT
+ </para>
+ <para>
+ Registered under <literal>long</literal> and
<literal>java.lang.Long</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.float">
+ <title><classname>java.lang.Float</classname> (or float
primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.FloatType</classname></term>
+ <listitem>
+ <para>
+ Maps a float or
<classname>java.lang.Float</classname> to a JDBC FLOAT
+ </para>
+ <para>
+ Registered under <literal>float</literal> and
<literal>java.lang.Float</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.double">
+ <title><classname>java.lang.Double</classname> (or
double primitive)</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.DoubleType</classname></term>
+ <listitem>
+ <para>
+ Maps a double or
<classname>java.lang.Double</classname> to a JDBC DOUBLE
+ </para>
+ <para>
+ Registered under <literal>double</literal>
and <literal>java.lang.Double</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.biginteger">
+
<title><classname>java.math.BigInteger</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BigIntegerType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.math.BigInteger</classname> to a JDBC NUMERIC
+ </para>
+ <para>
+ Registered under
<literal>big_integer</literal> and
<literal>java.math.BigInteger</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.bigdecimal">
+
<title><classname>java.math.BigDecimal</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BigDecimalType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.math.BigDecimal</classname> to a JDBC NUMERIC
+ </para>
+ <para>
+ Registered under
<literal>big_decimal</literal> and
<literal>java.math.BigDecimal</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.timestamp">
+ <title><classname>java.util.Date</classname> or
<classname>java.sql.Timestamp</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.TimestampType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.sql.Timestamp</classname> to a JDBC TIMESTAMP
+ </para>
+ <para>
+ Registered under
<literal>timestamp</literal>,
<literal>java.sql.Timestamp</literal> and
+ <literal>java.util.Date</literal> in the type
registry (see <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.time">
+
<title><classname>java.sql.Time</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.TimeType</classname></term>
+ <listitem>
+ <para>
+ Maps a <classname>java.sql.Time</classname>
to a JDBC TIME
+ </para>
+ <para>
+ Registered under <literal>time</literal> and
<literal>java.sql.Time</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.date">
+
<title><classname>java.sql.Date</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.DateType</classname></term>
+ <listitem>
+ <para>
+ Maps a <classname>java.sql.Date</classname>
to a JDBC DATE
+ </para>
+ <para>
+ Registered under <literal>date</literal> and
<literal>java.sql.Date</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.calendar">
+
<title><classname>java.util.Calendar</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CalendarType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.util.Calendar</classname> to a JDBC TIMESTAMP
+ </para>
+ <para>
+ Registered under <literal>calendar</literal>,
<literal>java.util.Calendar</literal> and
+
<literal>java.util.GregorianCalendar</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CalendarDateType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.util.Calendar</classname> to a JDBC DATE
+ </para>
+ <para>
+ Registered under
<literal>calendar_date</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.currency">
+
<title><classname>java.util.Currency</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CurrencyType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.util.Currency</classname> to a JDBC VARCHAR (using the
Currency code)
+ </para>
+ <para>
+ Registered under <literal>currency</literal>
and <literal>java.util.Currency</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.locale">
+
<title><classname>java.util.Locale</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.LocaleType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.util.Locale</classname> to a JDBC VARCHAR (using the Locale
code)
+ </para>
+ <para>
+ Registered under <literal>locale</literal>
and <literal>java.util.Locale</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.timezone">
+
<title><classname>java.util.TimeZone</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.TimeZoneType</classname></term>
+ <listitem>
+ <para>
+ Maps a
<classname>java.util.TimeZone</classname> to a JDBC VARCHAR (using the
TimeZone ID)
+ </para>
+ <para>
+ Registered under <literal>timezone</literal>
and <literal>java.util.TimeZone</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.class">
+
<title><classname>java.lang.Class</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.ClassType</classname></term>
+ <listitem>
+ <para>
+ Maps a <classname>java.lang.Class</classname>
to a JDBC VARCHAR (using the Class name)
+ </para>
+ <para>
+ Registered under <literal>class</literal> and
<literal>java.lang.Class</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.blob">
+
<title><classname>java.sql.Blob</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BlobType</classname></term>
+ <listitem>
+ <para>
+ Maps a <classname>java.sql.Blob</classname>
to a JDBC BLOB
+ </para>
+ <para>
+ Registered under <literal>blob</literal> and
<literal>java.sql.Blob</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.clob">
+
<title><classname>java.sql.Clob</classname></title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.ClobType</classname></term>
+ <listitem>
+ <para>
+ Maps a <classname>java.sql.Clob</classname>
to a JDBC CLOB
+ </para>
+ <para>
+ Registered under <literal>clob</literal> and
<literal>java.sql.Clob</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.binary">
+ <title>byte[]</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BinaryType</classname></term>
+ <listitem>
+ <para>
+ Maps a primitive byte[] to a JDBC VARBINARY
+ </para>
+ <para>
+ Registered under <literal>binary</literal>
and <literal>byte[]</literal> in the
+ type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><classname>org.hibernate.type.MaterializedBlobType</classname></term>
+ <listitem>
+ <para>
+ Maps a primitive byte[] to a JDBC BLOB
+ </para>
+ <para>
+ Registered under
<literal>materialized_blob</literal> in the type registry (see
+ <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.wrapperbinary">
+ <title>byte[]</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.BinaryType</classname></term>
+ <listitem>
+ <para>
+ Maps a java.lang.Byte[] to a JDBC VARBINARY
+ </para>
+ <para>
+ Registered under
<literal>wrapper-binary</literal>, <literal>Byte[]</literal> and
+ <literal>java.lang.Byte[]</literal> in the
type registry (see <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.chararray">
+ <title>char[]</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CharArrayType</classname></term>
+ <listitem>
+ <para>
+ Maps a char[] to a JDBC VARCHAR
+ </para>
+ <para>
+ Registered under
<literal>characters</literal> and <literal>char[]</literal>
+ in the type registry (see <xref
linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.characterarray">
+ <title>char[]</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.CharacterArrayType</classname></term>
+ <listitem>
+ <para>
+ Maps a java.lang.Character[] to a JDBC VARCHAR
+ </para>
+ <para>
+ Registered under
<literal>wrapper-characters</literal>,
<literal>Character[]</literal>
+ and <literal>java.lang.Character[]</literal>
in the type registry (see <xref linkend="types.registry"/>).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="types.basic.value.serializable">
+ <title>java.io.Serializable</title>
+ <variablelist>
+ <varlistentry>
+
<term><classname>org.hibernate.type.SerializableType</classname></term>
+ <listitem>
+ <para>
+ Maps implementors of java.lang.Serializable to a JDBC
VARBINARY
+ </para>
+ <para>
+ Unlike the other value types, there are multiple
instances of this type. It
+ gets registered once under
<literal>java.io.Serializable</literal>. Additionally it
+ gets registered under the specific
<interfacename>java.io.Serializable</interfacename>
+ implementation class names.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </section>
+
+ <section id="types.value.composite">
+ <title>Composite types</title>
+ <note>
+ <para>
+ The Java Persistence API calls these embedded types, while Hibernate
traditionally called them
+ components. Just be aware that both terms are used and mean the same
thing in the scope of
+ discussing Hibernate.
+ </para>
+ </note>
+ <para>
+ Components represent aggregations of values into a single Java type. For
example, you might have
+ an Address class that aggregates street, city, state, etc information or
a Name class that
+ aggregates the parts of a person's Name. In many ways a component
looks exactly like an entity. They
+ are both (generally speaking) classes written specifically for the
application. They both might have
+ references to other application-specific classes, as well as to
collections and simple JDK types. As
+ discussed before, the only distinguishing factory is the fact that a
component does not own its own
+ lifecycle.
+ </para>
+ </section>
+
+ <section id="types.value.collection">
+ <title>Collection types</title>
+ <important>
+ <para>
+ It is critical understand that we mean the collection itself, not its
contents.
+ The contents of the collection can in turn be basic, component or
entity types (though not
+ collections), but the collection itself is owned.
+ </para>
+ </important>
+ <para>
+ Collections are covered in <xref
linkend="collections"/>.
+ </para>
+ </section>
+
+ </section>
+
+ <section id="types.entity">
+ <title>Entity types</title>
+ <para>
+ The definition of entities is covered in detail in <xref
linkend="persistent-classes"/>. For the purpose of
+ this discussion, it is enough to say that entities are (generally
application-specific) classes which
+ correlate to rows in a table. Specifically they correlate to the row by
means of a unique identifier.
+ Because of this unique identifier, entities exist independently and define
their own lifecycle. As an example,
+ when we delete a <classname>Membership</classname>, both the
<classname>User</classname> and
+ <classname>Group</classname> entities remain.
+ <note>
+ <para>
+ This notion of entity independence can be modified by the application
developer using the concept of
+ cascades. Cascades allow certain operations to continue (or
"cascade") across an association from
+ one entity to another. Cascades are covered in detail in <xref
linkend="associations"/>.
+ </para>
+ </note>
+ </para>
+ </section>
+
+ <section id="types.category.significance">
+ <title>Significance of type categories</title>
+ <para>
+ Why do we spend so much time categorizing the various types of types? What
is the significance of the
+ distinction?
+ </para>
+ <para>
+ The main categorization was between entity types and value types. To review
we said that entities, by
+ nature of their unique identifier, exist independently of other objects
whereas values do not. An
+ application cannot "delete" a Product sku; instead, the sku is
removed when the Product itself is
+ deleted (obviously you can <emphasis>update</emphasis> the sku of
that Product to null to maker it
+ "go away", but even there the access is done through the Product).
+ </para>
+ <para>
+ Nor can you define an association <emphasis>to</emphasis> that
Product sku. You <emphasis>can</emphasis>
+ define an association to Product <emphasis>based on</emphasis>
its sku, assuming sku is unique but that
+ is totally different.
+
+
+ entity types define
+ data that maintains its own lifecycle, while value types define data that
only exists dependently. Essentially it defines it own unique identifier. In turn that
means
+ that it can be used to share references to that data from other entities (or
components or collections).
+ This dependence/independence has a few important ramifications:
+ <itemizedlist>
+ <listitem>
+ <para>
+ First, entities can be looked up and referenced (as in foreign
keys). The same is not true of
+ a value type. For example, a
<classname>Product</classname> entity can be looked up by its
+ unique identifier. The sku of that Product
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section id="types.custom">
+ <title>Custom types</title>
+ <para>
+ Hibernate makes it relatively easy for developers to create their own
<emphasis>value</emphasis> types. For
+ example, you might want to persist properties of type
<classname>java.lang.BigInteger</classname> to
+ <literal>VARCHAR</literal> columns. Custom types are not limited
to mapping values to a single table
+ column. So, for example, you might want to concatenate together
<literal>FIRST_NAME</literal>,
+ <literal>INITIAL</literal> and
<literal>SURNAME</literal> columsn into a
<classname>java,lang.String</classname>.
+ </para>
+
+ <para>
+ There are 3 approaches to developing a custom Hibernate type. As a means of
illustrating the different
+ approaches, lets consider a use case where we need to compose a
<classname>java.math.BigDecimal</classname>
+ and <classname>java.util.Currency</classname> together into a
custom <classname>Money</classname> class.
+ </para>
+
+ <section id="types.custom.type">
+ <title>Custom types using
<interfacename>org.hibernate.type.Type</interfacename></title>
+ <para>
+ The first approach is to directly implement the
<interfacename>org.hibernate.type.Type</interfacename>
+ interface (or one of its derivatives). Probably, you will be more
interested in the more specific
+ <interfacename>org.hibernate.type.BasicType</interfacename>
contract which would allow registration of
+ the type (see <xref linkend="types.registry"/>). The
benefit of this registration is that whenever
+ the metadata for a particular property does not specify the Hibernate
type to use, Hibernate will
+ consult the registry for the exposed property type. In our example, the
property type would be
+ <classname>Money</classname>, which is the key we would use
to register our type in the registry:
+ <example id="types.custom.type.ex.definition">
+ <title>Defining and registering the custom Type</title>
+ <programlisting role="JAVA"><![CDATA[public class
MoneyType implements BasicType {
+ public String[] getRegistrationKeys() {
+ return new String[] { Money.class.getName() };
+ }
+
+ public int[] sqlTypes(Mapping mapping) {
+ // We will simply use delegation to the standard basic types for BigDecimal and
Currency for many of the
+ // Type methods...
+ return new int[] {
+ BigDecimalType.INSTANCE.sqlType(),
+ CurrencyType.INSTANCE.sqlType(),
+ };
+ // we could also have honored any registry overrides via...
+ //return new int[] {
+ // mappings.getTypeResolver().basic( BigDecimal.class.getName() ).sqlTypes(
mappings )[0],
+ // mappings.getTypeResolver().basic( Currency.class.getName() ).sqlTypes(
mappings )[0]
+ //};
+ }
+
+ public Class getReturnedClass() {
+ return Money.class;
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session,
Object owner) throws SQLException {
+ assert names.length == 2;
+ BigDecimal amount = BigDecimalType.INSTANCE.get( names[0] ); // already handles
null check
+ Currency currency = CurrencyType.INSTANCE.get( names[1] ); // already handles
null check
+ return amount == null && currency == null
+ ? null
+ : new Money( amount, currency );
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[]
settable, SessionImplementor session)
+ throws SQLException {
+ if ( value == null ) {
+ BigDecimalType.INSTANCE.set( st, null, index );
+ CurrencyType.INSTANCE.set( st, null, index+1 );
+ }
+ else {
+ final Money money = (Money) value;
+ BigDecimalType.INSTANCE.set( st, money.getAmount(), index );
+ CurrencyType.INSTANCE.set( st, money.getCurrency(), index+1 );
+ }
+ }
+
+ ...
+}]]></programlisting>
+ <programlisting role="JAVA">
+ Configuration cfg = new Configuration();
+ cfg.registerTypeOverride( new MoneyType() );
+ cfg...;
+ </programlisting>
+ </example>
+ <important>
+ <para>
+ It is important that we registered the type
<emphasis>before</emphasis> adding mappings.
+ </para>
+ </important>
+ </para>
+ </section>
+
+ <section id="types.custom.ut">
+ <title>Custom types using
<interfacename>org.hibernate.usertype.UserType</interfacename></title>
+ <note>
+ <para>
+ Both
<interfacename>org.hibernate.usertype.UserType</interfacename> and
+
<interfacename>org.hibernate.usertype.CompositeUserType</interfacename> were
originally
+ added to isolate user code from internal changes to the
<interfacename>org.hibernate.type.Type</interfacename>
+ interfaces.
+ </para>
+ </note>
+ <para>
+ The second approach is the use the
<interfacename>org.hibernate.usertype.UserType</interfacename>
+ interface, which presents a somewhat simplified view of the
<interfacename>org.hibernate.type.Type</interfacename>
+ interface. Using a
<interfacename>org.hibernate.usertype.UserType</interfacename>, our
+ <classname>Money</classname> custom type would look as
follows:
+ </para>
+ <example id="types.custom.ut.ex.definition">
+ <title>Defining the custom UserType</title>
+ <programlisting role="JAVA"><![CDATA[public class
MoneyType implements UserType {
+ public int[] sqlTypes() {
+ return new int[] {
+ BigDecimalType.INSTANCE.sqlType(),
+ CurrencyType.INSTANCE.sqlType(),
+ };
+ }
+
+ public Class getReturnedClass() {
+ return Money.class;
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws
SQLException {
+ assert names.length == 2;
+ BigDecimal amount = BigDecimalType.INSTANCE.get( names[0] ); // already handles
null check
+ Currency currency = CurrencyType.INSTANCE.get( names[1] ); // already handles
null check
+ return amount == null && currency == null
+ ? null
+ : new Money( amount, currency );
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index) throws
SQLException {
+ if ( value == null ) {
+ BigDecimalType.INSTANCE.set( st, null, index );
+ CurrencyType.INSTANCE.set( st, null, index+1 );
+ }
+ else {
+ final Money money = (Money) value;
+ BigDecimalType.INSTANCE.set( st, money.getAmount(), index );
+ CurrencyType.INSTANCE.set( st, money.getCurrency(), index+1 );
+ }
+ }
+
+ ...
+}]]></programlisting>
+ </example>
+ <para>
+ There is not much difference between the
<interfacename>org.hibernate.type.Type</interfacename> example
+ and the
<interfacename>org.hibernate.usertype.UserType</interfacename> example, but
that is only because
+ of the snippets shown. If you choose the
<interfacename>org.hibernate.type.Type</interfacename> approach
+ there are quite a few more methods you would need to implement as
compared to the
+
<interfacename>org.hibernate.usertype.UserType</interfacename>.
+ </para>
+ </section>
+
+ <section id="types.custom.cut">
+ <title>Custom types using
<interfacename>org.hibernate.usertype.CompositeUserType</interfacename></title>
+ <para>
+ The third and final approach is the use the
<interfacename>org.hibernate.usertype.CompositeUserType</interfacename>
+ interface, which differs from
<interfacename>org.hibernate.usertype.UserType</interfacename> in that it
+ gives us the ability to provide Hibernate the information to handle the
composition within the
+ <classname>Money</classname> class (specifically the 2
attributes). THis would give us the capability,
+ for example, to reference the <literal>amount</literal>
attribute in an HQL query. Using a
+
<interfacename>org.hibernate.usertype.UserType</interfacename>, our
<classname>Money</classname> custom
+ type would look as follows:
+ </para>
+
+ <example id="types.custom.cut.ex.definition">
+ <title>Defining the custom CompositeUserType</title>
+ <programlisting role="JAVA"><![CDATA[public class
MoneyType implements CompositeUserType {
+ public String[] getPropertyNames() {
+ // ORDER IS IMPORTANT! it must match the order the columns are defined in the
property mapping
+ return new String[] { "amount", "currency" };
+ }
+
+ public Type[] getPropertyTypes() {
+ return new Type[] { BigDecimalType.INSTANCE, CurrencyType.INSTANCE };
+ }
+
+ public Class getReturnedClass() {
+ return Money.class;
+ }
+
+ public Object getPropertyValue(Object component, int propertyIndex) {
+ if ( component == null ) {
+ return null;
+ }
+
+ final Money money = (Money) component;
+ switch ( propertyIndex ) {
+ case 0: {
+ return money.getAmount();
+ }
+ case 1: {
+ return money.getCurrency();
+ }
+ default: {
+ throw new HibernateException( "Invalid property index [" +
propertyIndex + "]" );
+ }
+ }
+ }
+
+ public void setPropertyValue(Object component, int propertyIndex, Object value) throws
HibernateException {
+ if ( component == null ) {
+ return;
+ }
+
+ final Money money = (Money) component;
+ switch ( propertyIndex ) {
+ case 0: {
+ money.setAmount( (BigDecimal) value );
+ break;
+ }
+ case 1: {
+ money.setCurrency( (Currency) value );
+ break;
+ }
+ default: {
+ throw new HibernateException( "Invalid property index [" +
propertyIndex + "]" );
+ }
+ }
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session,
Object owner) throws SQLException {
+ assert names.length == 2;
+ BigDecimal amount = BigDecimalType.INSTANCE.get( names[0] ); // already handles
null check
+ Currency currency = CurrencyType.INSTANCE.get( names[1] ); // already handles
null check
+ return amount == null && currency == null
+ ? null
+ : new Money( amount, currency );
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws SQLException {
+ if ( value == null ) {
+ BigDecimalType.INSTANCE.set( st, null, index );
+ CurrencyType.INSTANCE.set( st, null, index+1 );
+ }
+ else {
+ final Money money = (Money) value;
+ BigDecimalType.INSTANCE.set( st, money.getAmount(), index );
+ CurrencyType.INSTANCE.set( st, money.getCurrency(), index+1 );
+ }
+ }
+
+ ...
+}]]></programlisting>
+ </example>
+ </section>
+
+ </section>
+
+ <section id="types.registry">
+ <title>Type registry</title>
+ <para>
+ Internally Hibernate uses a registry of basic types (see <xref
linkend="types.value.basic"/>) when
+ it needs to resolve the specific
<interfacename>org.hibernate.type.Type</interfacename> to use in certain
+ situations. It also provides a way for applications to add extra basic type
registrations as well as
+ override the standard basic type registrations.
+ </para>
+ <para>
+ To register a new type or to override an existing type registration,
applications would make use of the
+ <methodname>registerTypeOverride</methodname> method of the
<classname>org.hibernate.cfg.Configuration</classname>
+ class when bootstrapping Hibernate. For example, lets say you want Hibernate
to use your custom
+ <classname>SuperDuperStringType</classname>; during bootstrap you
would call:
+ <example id="type.registry.override.ex">
+ <title>Overriding the standard
<classname>StringType</classname></title>
+ <programlisting role="JAVA"><![CDATA[Configuration cfg
= ...;
+ cfg.registerTypeOverride( new SuperDuperStringType() );]]></programlisting>
+ </example>
+ </para>
+ <para>
+ The argument to <methodname>registerTypeOverride</methodname> is
a <interfacename>org.hibernate.type.BasicType</interfacename>
+ which is a specialization of the
<interfacename>org.hibernate.type.Type</interfacename> we saw before. It
+ adds a single method:
+ <example>
+ <title>Snippet from BasicType.java</title>
+ <programlisting role="JAVA" >
+ /**
+ * Get the names under which this type should be registered in the type registry.
+ *
+ * @return The keys under which to register this type.
+ */
+ public String[] getRegistrationKeys();
+ </programlisting>
+ </example>
+ One approach is to use inheritance
(<classname>SuperDuperStringType</classname> extends
+ <classname>org.hibernate.typeStringType</classname>). Another
approach is to use delegation.
+ </para>
+ <important>
+ <para>
+ Currently UserType and CompositeUserType cannot be registered with the
registry. See
+ <ulink
url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-5...
for details.
+ </para>
+ </important>
+ </section>
+
+</chapter>