HHH-3760 : document EntityNameResolver

git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_3@15931 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-02-10 21:44:33 +00:00
parent e8f38ede57
commit 098586a4f0
1 changed files with 147 additions and 1 deletions

View File

@ -551,11 +551,157 @@ public class CustomMapTuplizerImpl
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>