HHH-5397 - Odds and ends from documentation merge : persistent_classes.xml

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19978 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2010-07-21 00:58:10 +00:00
parent 17261e1e06
commit 249127b8c0
1 changed files with 241 additions and 210 deletions

View File

@ -2,10 +2,10 @@
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ 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 Middleware LLC.
~ 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
@ -27,39 +27,40 @@
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
]>
<chapter id="persistent-classes" revision="2">
<title>Persistent Classes</title>
<para>Persistent classes are classes in an application that implement the
entities of the business problem (e.g. Customer and Order in an E-commerce
application). Not all instances of a persistent class are considered to be
in the persistent state. For example, an instance can instead be transient
or detached.</para>
<chapter id="persistent-classes">
<title>Persistent Classes</title>
<para>Hibernate works best if these classes follow some simple rules, also
known as the Plain Old Java Object (POJO) programming model. However, none
of these rules are hard requirements. Indeed, Hibernate3 assumes very little
about the nature of your persistent objects. You can express a domain model
in other ways (using trees of <literal>Map</literal> instances, for
example).</para>
<para>
Persistent classes are classes in an application that implement the entities of the business problem
(e.g. Customer and Order in an E-commerce application). The term "persistent" here means that the classes
are able to be persisted, not that they are in the persistent state (see <xref linkend="objectstate-overview"/>
for discussion).
</para>
<section id="persistent-classes-pojo">
<title>A simple POJO example</title>
<para>
Hibernate works best if these classes follow some simple rules, also known as the Plain Old Java Object (POJO)
programming model. However, none of these rules are hard requirements. Indeed, Hibernate assumes very little
about the nature of your persistent objects. You can express a domain model in other ways (using trees of
<interfacename>java.util.Map</interfacename> instances, for example).
</para>
<para>Most Java applications require a persistent class representing
felines. For example:</para>
<section id="persistent-classes-pojo">
<title>A simple POJO example</title>
<programlisting role="JAVA">package eg;
<example id="persistent-classes-pojo-example-cat">
<title>Simple POJO representing a cat</title>
<programlisting role="JAVA">package eg;
import java.util.Set;
import java.util.Date;
public class Cat {
private Long id; // identifier
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
@ -119,108 +120,137 @@ public class Cat {
public Set getKittens() {
return kittens;
}
// addKitten not needed by Hibernate
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}</programlisting>
</example>
<para>The four main rules of persistent classes are explored in more
detail in the following sections.</para>
<section id="persistent-classes-pojo-constructor" revision="1">
<title>Implement a no-argument constructor</title>
<para>
The four main rules of persistent classes are explored in more detail in the following sections.
</para>
<para><literal>Cat</literal> has a no-argument constructor. All
persistent classes must have a default constructor (which can be
non-public) so that Hibernate can instantiate them using
<literal>Constructor.newInstance()</literal>. It is recommended that you
have a default constructor with at least <emphasis>package</emphasis>
visibility for runtime proxy generation in Hibernate.</para>
<section id="persistent-classes-pojo-constructor">
<title>Implement a no-argument constructor</title>
<para>
<classname>Cat</classname> has a no-argument constructor. All persistent classes must have a default
constructor (which can be non-public) so that Hibernate can instantiate them using
<literal><classname>java.lang.reflect.Constructor</classname>.newInstance()</literal>. It is recommended
that this constructor be defined with at least <emphasis>package</emphasis> visibility in order for
runtime proxy generation to work properly.
</para>
</section>
<section id="persistent-classes-pojo-identifier" revision="2">
<title>Provide an identifier property</title>
<note>
<para>
Historically this was considered option. While still not (yet) enforced, this should be considered
a deprecated feature as it will be completely required to provide a identifier property in an
upcoming release.
</para>
</note>
<para>
<classname>Cat</classname> has a property named <literal>id</literal>. This property maps to the
primary key column(s) of the underlying database table. The type of the identifier property can
be any "basic" type (see <xref linkend="types.value.basic"/>). See <xref linkend="components-compositeid"/>
for information on mapping composite (multi-column) identifiers.
</para>
<note>
<para>
Identifiers do not necessarily need to identify column(s) in the database physically defined
as a primary key. They should just identify columns that can be used to uniquely identify rows
in the underlying table.
</para>
</note>
<para>
We recommend that you declare consistently-named identifier properties on persistent classes and that you use
a nullable (i.e., non-primitive) type.
</para>
</section>
<section id="persistent-classes-pojo-final">
<title>Prefer non-final classes (semi-optional)</title>
<para>
A central feature of Hibernate, <emphasis>proxies</emphasis> (lazy loading), depends upon the
persistent class being either non-final, or the implementation of an interface that declares all public
methods. You can persist <literal>final</literal> classes that do not implement an interface with
Hibernate; you will not, however, be able to use proxies for lazy association fetching which will
ultimately limit your options for performance tuning. To persist a <literal>final</literal>
class which does not implement a "full" interface you must disable proxy generation. See
<xref linkend="persistent-classes-pojo-final-example-disable-proxies-xml"/> and
<xref linkend="persistent-classes-pojo-final-example-disable-proxies-ann"/>.
</para>
<example id="persistent-classes-pojo-final-example-disable-proxies-xml">
<title>Disabling proxies in <literal>hbm.xml</literal></title>
<programlisting role="XML"><![CDATA[<class name="Cat" lazy="false"...>...</class>]]></programlisting>
</example>
<example id="persistent-classes-pojo-final-example-disable-proxies-ann">
<title>Disabling proxies in annotations</title>
<programlisting role="JAVA"><![CDATA[@Entity @Proxy(lazy=false) public class Cat { ... }]]></programlisting>
</example>
<para>
If the <literal>final</literal> class does implement a proper interface, you could alternatively tell
Hibernate to use the interface instead when generating the proxies. See
<xref linkend="persistent-classes-pojo-final-example-proxy-interface-xml"/> and
<xref linkend="persistent-classes-pojo-final-example-proxy-interface-ann"/>.
</para>
<example id="persistent-classes-pojo-final-example-proxy-interface-xml">
<title>Proxying an interface in <literal>hbm.xml</literal></title>
<programlisting role="XML"><![CDATA[<class name="Cat" proxy="ICat"...>...</class>]]></programlisting>
</example>
<example id="persistent-classes-pojo-final-example-proxy-interface-ann">
<title>Proxying an interface in annotations</title>
<programlisting role="JAVA"><![CDATA[@Entity @Proxy(proxyClass=ICat.class) public class Cat implements ICat { ... }]]></programlisting>
</example>
<para>
You should also avoid declaring <literal>public final</literal> methods as this will again limit
the ability to generate <emphasis>proxies</emphasis> from this class. If you want to use a
class with <literal>public final</literal> methods, you must explicitly disable proxying. Again, see
<xref linkend="persistent-classes-pojo-final-example-disable-proxies-xml"/> and
<xref linkend="persistent-classes-pojo-final-example-disable-proxies-ann"/>.
</para>
</section>
<section id="persistent-classes-pojo-accessors">
<title>Declare accessors and mutators for persistent fields (optional)</title>
<para>
<classname>Cat</classname> declares accessor methods for all its persistent fields. Many other ORM
tools directly persist instance variables. It is better to provide an indirection between the relational
schema and internal data structures of the class. By default, Hibernate persists JavaBeans style
properties and recognizes method names of the form <literal>getFoo</literal>, <literal>isFoo</literal>
and <literal>setFoo</literal>. If required, you can switch to direct field access for particular
properties.
</para>
<para>
Properties need <emphasis>not</emphasis> be declared public. Hibernate can persist a property declared
with <literal>package</literal>, <literal>protected</literal> or <literal>private</literal> visibility
as well.
</para>
</section>
</section>
<section id="persistent-classes-pojo-identifier" revision="2">
<title>Provide an identifier property (optional)</title>
<para><literal>Cat</literal> has a property called
<literal>id</literal>. This property maps to the primary key column of a
database table. The property might have been called anything, and its
type might have been any primitive type, any primitive "wrapper" type,
<literal>java.lang.String</literal> or
<literal>java.util.Date</literal>. If your legacy database table has
composite keys, you can use a user-defined class with properties of
these types (see the section on composite identifiers later in the
chapter.)</para>
<para>The identifier property is strictly optional. You can leave them
off and let Hibernate keep track of object identifiers internally. We do
not recommend this, however.</para>
<para>In fact, some functionality is available only to classes that
declare an identifier property:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Transitive reattachment for detached objects (cascade update
or cascade merge) - see <xref
linkend="objectstate-transitive" /></para>
</listitem>
<listitem>
<para><literal>Session.saveOrUpdate()</literal></para>
</listitem>
<listitem>
<para><literal>Session.merge()</literal></para>
</listitem>
</itemizedlist>
<para>We recommend that you declare consistently-named identifier
properties on persistent classes and that you use a nullable (i.e.,
non-primitive) type.</para>
</section>
<section id="persistent-classes-pojo-final">
<title>Prefer non-final classes (optional)</title>
<para>A central feature of Hibernate, <emphasis>proxies</emphasis>,
depends upon the persistent class being either non-final, or the
implementation of an interface that declares all public methods.</para>
<para>You can persist <literal>final</literal> classes that do not
implement an interface with Hibernate. You will not, however, be able to
use proxies for lazy association fetching which will ultimately limit
your options for performance tuning.</para>
<para>You should also avoid declaring <literal>public final</literal>
methods on the non-final classes. If you want to use a class with a
<literal>public final</literal> method, you must explicitly disable
proxying by setting <literal>lazy="false"</literal>.</para>
</section>
<section id="persistent-classes-pojo-accessors" revision="2">
<title>Declare accessors and mutators for persistent fields
(optional)</title>
<para><literal>Cat</literal> declares accessor methods for all its
persistent fields. Many other ORM tools directly persist instance
variables. It is better to provide an indirection between the relational
schema and internal data structures of the class. By default, Hibernate
persists JavaBeans style properties and recognizes method names of the
form <literal>getFoo</literal>, <literal>isFoo</literal> and
<literal>setFoo</literal>. If required, you can switch to direct field
access for particular properties.</para>
<para>Properties need <emphasis>not</emphasis> be declared public -
Hibernate can persist a property with a default,
<literal>protected</literal> or <literal>private</literal> get / set
pair.</para>
</section>
</section>
<section id="persistent-classes-inheritance">
<title>Implementing inheritance</title>
@ -447,44 +477,53 @@ dynamicSession.close()
found in <xref linkend="xml" />.</para>
</section>
<section id="persistent-classes-tuplizers" revision="1">
<title>Tuplizers</title>
<para><literal>org.hibernate.tuple.Tuplizer</literal>, and its
sub-interfaces, are responsible for managing a particular representation
of a piece of data given that representation's
<literal>org.hibernate.EntityMode</literal>. If a given piece of data is
thought of as a data structure, then a tuplizer is the thing that knows
how to create such a data structure and how to extract values from and
inject values into such a data structure. For example, for the POJO entity
mode, the corresponding tuplizer knows how create the POJO through its
constructor. It also knows how to access the POJO properties using the
defined property accessors.</para>
<section id="persistent-classes-tuplizers" revision="1">
<title>Tuplizers</title>
<para>There are two high-level types of Tuplizers, represented by the
<literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and
<literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
interfaces. <literal>EntityTuplizer</literal>s are responsible for
managing the above mentioned contracts in regards to entities, while
<literal>ComponentTuplizer</literal>s do the same for components.</para>
<para>
<interfacename>org.hibernate.tuple.Tuplizer</interfacename> and its sub-interfaces are responsible for
managing a particular representation of a piece of data given that representation's
<classname>org.hibernate.EntityMode</classname>. If a given piece of data is thought of as a data
structure, then a tuplizer is the thing that knows how to create such a data structure, how to extract
values from such a data structure and how to inject values into such a data structure. For example, for
the POJO entity mode, the corresponding tuplizer knows how create the POJO through its constructor.
It also knows how to access the POJO properties using the defined property accessors.
</para>
<para>Users can also plug in their own tuplizers. Perhaps you require that
a <literal>java.util.Map</literal> implementation other than
<literal>java.util.HashMap</literal> be used while in the dynamic-map
entity-mode. Or perhaps you need to define a different proxy generation
strategy than the one used by default. Both would be achieved by defining
a custom tuplizer implementation. Tuplizer definitions are attached to the
entity or component mapping they are meant to manage. Going back to the
example of our customer entity <xref
linkend="example-defining-tuplizer-using-annotations" /> shows how to
configure tuplizers using annotations whereas <xref
linkend="example-defining-tuplizer-using-mapping-file" /> shows how to do
the same thing using Hibernate mapping files.</para>
<para>
There are two (high-level) types of Tuplizers:
<itemizedlist>
<listitem>
<para>
<interfacename>org.hibernate.tuple.entity.EntityTuplizer</interfacename> which is
responsible for managing the above mentioned contracts in regards to entities
</para>
</listitem>
<listitem>
<para>
<interfacename>org.hibernate.tuple.component.ComponentTuplizer</interfacename> which does the
same for components
</para>
</listitem>
</itemizedlist>
</para>
<example id="example-defining-tuplizer-using-annotations">
<title>Mapping custom tuplizers using annotations</title>
<para>
Users can also plug in their own tuplizers. Perhaps you require that
<interfacename>java.util.Map</interfacename> implementation other than
<classname>java.util.HashMap</classname> be used while in the dynamic-map entity-mode. Or perhaps you
need to define a different proxy generation strategy than the one used by default. Both would be achieved
by defining a custom tuplizer implementation. Tuplizer definitions are attached to the entity or component
mapping they are meant to manage. Going back to the example of our <classname>Customer</classname> entity,
<xref linkend="example-specify-custom-tuplizer-ann"/> shows how to specify a custom
<interfacename>org.hibernate.tuple.entity.EntityTuplizer</interfacename> using annotations while
<xref linkend="example-specify-custom-tuplizer-xml"/> shows how to do the same in <literal>hbm.xml</literal>
</para>
<programlisting role="XML">@Entity
<example id="example-specify-custom-tuplizer-ann">
<title>Specify custom tuplizers in annotations</title>
<programlisting role="JAVA">@Entity
@Tuplizer(impl = DynamicEntityTuplizer.class)
public interface Cuisine {
@Id
@ -499,13 +538,10 @@ public interface Cuisine {
public Country getCountry();
public void setCountry(Country country);
}</programlisting>
</example>
<example>
<title id="example-defining-tuplizer-using-mapping-file">Mapping custom
tuplizers using mapping files</title>
<programlisting role="XML">&lt;hibernate-mapping&gt;
</example>
<example id="example-specify-custom-tuplizer-xml">
<title>Specify custom tuplizers in <literal>hbm.xml</literal></title>
<programlisting role="XML">&lt;hibernate-mapping&gt;
&lt;class entity-name="Customer"&gt;
&lt;!--
Override the dynamic-map entity-mode
@ -521,33 +557,29 @@ public interface Cuisine {
&lt;!-- other properties --&gt;
...
&lt;/class&gt;
&lt;/hibernate-mapping&gt;
</programlisting>
</example>
</section>
&lt;/hibernate-mapping&gt;</programlisting>
</example>
</section>
<section id="persistent-classes-entity-name-resolver" revision="0">
<title>EntityNameResolvers</title>
<section id="persistent-classes-entity-name-resolver">
<title>EntityNameResolvers</title>
<para>The <interfacename>org.hibernate.EntityNameResolver</interfacename>
interface is a contract for resolving the entity name of a given entity
instance. The interface defines a single method
<methodname>resolveEntityName</methodname> which is passed the entity
instance and is expected to return the appropriate entity name (null is
allowed and would indicate that the resolver does not know how to resolve
the entity name of the given entity instance). Generally speaking, an
<interfacename>org.hibernate.EntityNameResolver</interfacename> is going
to be most useful in the case of dynamic models. One example might be
using proxied interfaces as your domain model. The hibernate test suite
has an example of this exact style of usage under the
<package>org.hibernate.test.dynamicentity.tuplizer2</package>. Here is
some of the code from that package for illustration.</para>
<para>
<interfacename>org.hibernate.EntityNameResolver</interfacename> is a contract for resolving the entity name
of a given entity instance. The interface defines a single method <methodname>resolveEntityName</methodname>
which is passed the entity instance and is expected to return the appropriate entity name (null is
allowed and would indicate that the resolver does not know how to resolve the entity name of the given entity
instance). Generally speaking, an <interfacename>org.hibernate.EntityNameResolver</interfacename> is going
to be most useful in the case of dynamic models. One example might be using proxied interfaces as your
domain model. The hibernate test suite has an example of this exact style of usage under the
<package>org.hibernate.test.dynamicentity.tuplizer2</package>. Here is some of the code from that package
for illustration.
</para>
<programlisting role="JAVA">
/**
* A very trivial JDK Proxy InvocationHandler implementation where we proxy an interface as
* the domain model and simply store persistent state in an internal Map. This is an extremely
* trivial example meant only for illustration.
<programlisting role="JAVA">/**
* A very trivial JDK Proxy InvocationHandler implementation where we proxy an
* interface as the domain model and simply store persistent state in an internal
* Map. This is an extremely trivial example meant only for illustration.
*/
public final class DataProxyHandler implements InvocationHandler {
private String entityName;
@ -586,9 +618,6 @@ public final class DataProxyHandler implements InvocationHandler {
}
}
/**
*
*/
public class ProxyHelper {
public static String extractEntityName(Object object) {
// Our custom java.lang.reflect.Proxy instances actually bundle
@ -610,12 +639,14 @@ public class ProxyHelper {
/**
* The EntityNameResolver implementation.
* IMPL NOTE : An EntityNameResolver really defines a strategy for how entity names should be
* resolved. Since this particular impl can handle resolution for all of our entities we want to
* take advantage of the fact that SessionFactoryImpl keeps these in a Set so that we only ever
* have one instance registered. Why? Well, when it comes time to resolve an entity name,
* Hibernate must iterate over all the registered resolvers. So keeping that number down
* helps that process be as speedy as possible. Hence the equals and hashCode impls
*
* IMPL NOTE : An EntityNameResolver really defines a strategy for how entity names
* should be resolved. Since this particular impl can handle resolution for all of our
* entities we want to take advantage of the fact that SessionFactoryImpl keeps these
* in a Set so that we only ever have one instance registered. Why? Well, when it
* comes time to resolve an entity name, Hibernate must iterate over all the registered
* resolvers. So keeping that number down helps that process be as speedy as possible.
* Hence the equals and hashCode implementations as is
*/
public class MyEntityNameResolver implements EntityNameResolver {
public static final MyEntityNameResolver INSTANCE = new MyEntityNameResolver();
@ -651,26 +682,26 @@ public class MyEntityTuplizer extends PojoEntityTuplizer {
}
...
}
</programlisting>
</programlisting>
<para>In order to register an
<interfacename>org.hibernate.EntityNameResolver</interfacename> users must
either: <orderedlist>
<listitem>
<para>Implement a custom <link
linkend="persistent-classes-tuplizers">Tuplizer</link>, implementing
the <methodname>getEntityNameResolvers</methodname> method.</para>
</listitem>
<para>
In order to register an <interfacename>org.hibernate.EntityNameResolver</interfacename> users must either:
<orderedlist>
<listitem>
<para>
Implement a custom tuplizer (see <xref linkend="persistent-classes-tuplizers"/>), implementing
the <methodname>getEntityNameResolvers</methodname> method
</para>
</listitem>
<listitem>
<para>
Register it with the <classname>org.hibernate.impl.SessionFactoryImpl</classname> (which is the
implementation class for <interfacename>org.hibernate.SessionFactory</interfacename>) using the
<methodname>registerEntityNameResolver</methodname> method.
</para>
</listitem>
</orderedlist>
</para>
</section>
<listitem>
<para>Register it with the
<classname>org.hibernate.impl.SessionFactoryImpl</classname> (which
is the implementation class for
<interfacename>org.hibernate.SessionFactory</interfacename>) using
the <methodname>registerEntityNameResolver</methodname>
method.</para>
</listitem>
</orderedlist></para>
</section>
</chapter>