Author: steve.ebersole(a)jboss.com
Date: 2009-02-10 16:44:48 -0500 (Tue, 10 Feb 2009)
New Revision: 15932
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml
Log:
HHH-3760 : document EntityNameResolver
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml
===================================================================
---
core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml 2009-02-10
21:44:33 UTC (rev 15931)
+++
core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml 2009-02-10
21:44:48 UTC (rev 15932)
@@ -551,11 +551,158 @@
return new CustomMap();
}
}
-}]]></programlisting>m
+}]]></programlisting>
</sect1>
+
+ <sect1 id="persistent-classes-entity-name-resolver"
revision="0">
+ <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>
+
+ <programlisting>
+/**
+ * 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;
+ private HashMap data = new HashMap();
+
+ public DataProxyHandler(String entityName, Serializable id) {
+ this.entityName = entityName;
+ data.put( "Id", id );
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ if ( methodName.startsWith( "set" ) ) {
+ String propertyName = methodName.substring( 3 );
+ data.put( propertyName, args[0] );
+ }
+ else if ( methodName.startsWith( "get" ) ) {
+ String propertyName = methodName.substring( 3 );
+ return data.get( propertyName );
+ }
+ else if ( "toString".equals( methodName ) ) {
+ return entityName + "#" + data.get( "Id" );
+ }
+ else if ( "hashCode".equals( methodName ) ) {
+ return new Integer( this.hashCode() );
+ }
+ return null;
+ }
+
+ public String getEntityName() {
+ return entityName;
+ }
+
+ public HashMap getData() {
+ return data;
+ }
+}
+
+/**
+ *
+ */
+public class ProxyHelper {
+ public static String extractEntityName(Object object) {
+ // Our custom java.lang.reflect.Proxy instances actually bundle
+ // their appropriate entity name, so we simply extract it from there
+ // if this represents one of our proxies; otherwise, we return null
+ if ( Proxy.isProxyClass( object.getClass() ) ) {
+ InvocationHandler handler = Proxy.getInvocationHandler( object );
+ if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) {
+ DataProxyHandler myHandler = ( DataProxyHandler ) handler;
+ return myHandler.getEntityName();
+ }
+ }
+ return null;
+ }
+
+ // various other utility methods ....
+
+}
+
+/**
+ * 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
+ */
+public class MyEntityNameResolver implements EntityNameResolver {
+ public static final MyEntityNameResolver INSTANCE = new MyEntityNameResolver();
+
+ public String resolveEntityName(Object entity) {
+ return ProxyHelper.extractEntityName( entity );
+ }
+
+ public boolean equals(Object obj) {
+ return getClass().equals( obj.getClass() );
+ }
+
+ public int hashCode() {
+ return getClass().hashCode();
+ }
+}
+
+public class MyEntityTuplizer extends PojoEntityTuplizer {
+ public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity)
{
+ super( entityMetamodel, mappedEntity );
+ }
+
+ public EntityNameResolver[] getEntityNameResolvers() {
+ return new EntityNameResolver[] { MyEntityNameResolver.INSTANCE };
+ }
+
+ public String determineConcreteSubclassEntityName(Object entityInstance,
SessionFactoryImplementor factory) {
+ String entityName = ProxyHelper.extractEntityName( entityInstance );
+ if ( entityName == null ) {
+ entityName = super.determineConcreteSubclassEntityName( entityInstance,
factory );
+ }
+ return entityName;
+ }
+
+ ...
+}
+ </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>
+ <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>
+ </sect1>
+
<!--<sect1 id="persistent-classes-extensions">
<title>Extensions</title>
<para>
Show replies by date