git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19607 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
30ea7142e8
commit
a05dc9066a
|
@ -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-5262"/> for details.
|
||||
</para>
|
||||
</important>
|
||||
</section>
|
||||
|
||||
</chapter>
|
Loading…
Reference in New Issue