HHH-3517 : default Tuplizer impls

git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@15289 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2008-10-08 17:23:01 +00:00
parent c24cab0092
commit 969ba9a900
10 changed files with 653 additions and 147 deletions

View File

@ -38,6 +38,7 @@ import org.hibernate.InvalidMappingException;
import org.hibernate.MappingException;
import org.hibernate.MappingNotFoundException;
import org.hibernate.SessionFactory;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
@ -133,6 +134,10 @@ public class Configuration implements Serializable {
protected Map sqlFunctions;
protected Map namedQueries;
protected Map namedSqlQueries;
private EntityTuplizerFactory entityTuplizerFactory;
// private ComponentTuplizerFactory componentTuplizerFactory; todo : HHH-3517 and HHH-1907
/**
* Map<String, SqlResultSetMapping> result set name, result set description
*/
@ -158,6 +163,17 @@ public class Configuration implements Serializable {
protected final SettingsFactory settingsFactory;
private transient Mapping mapping = buildMapping();
protected Configuration(SettingsFactory settingsFactory) {
this.settingsFactory = settingsFactory;
reset();
}
public Configuration() {
this( new SettingsFactory() );
}
protected void reset() {
classes = new HashMap();
imports = new HashMap();
@ -182,20 +198,17 @@ public class Configuration implements Serializable {
columnNameBindingPerTable = new HashMap();
namingStrategy = DefaultNamingStrategy.INSTANCE;
sqlFunctions = new HashMap();
entityTuplizerFactory = new EntityTuplizerFactory();
// componentTuplizerFactory = new ComponentTuplizerFactory();
}
private transient Mapping mapping = buildMapping();
protected Configuration(SettingsFactory settingsFactory) {
this.settingsFactory = settingsFactory;
reset();
public EntityTuplizerFactory getEntityTuplizerFactory() {
return entityTuplizerFactory;
}
public Configuration() {
this( new SettingsFactory() );
}
// public ComponentTuplizerFactory getComponentTuplizerFactory() {
// return componentTuplizerFactory;
// }
/**
* Iterate the entity mappings
@ -2066,11 +2079,18 @@ public class Configuration implements Serializable {
public Settings buildSettings() throws HibernateException {
Properties clone = ( Properties ) properties.clone();
PropertiesHelper.resolvePlaceHolders( clone );
return settingsFactory.buildSettings( clone );
return buildSettingsInternal( clone );
}
public Settings buildSettings(Properties props) throws HibernateException {
return settingsFactory.buildSettings( props );
return buildSettingsInternal( props );
}
private Settings buildSettingsInternal(Properties props) {
final Settings settings = settingsFactory.buildSettings( props );
settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() );
// settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() );
return settings;
}
public Map getNamedSQLQueries() {

View File

@ -14,6 +14,7 @@ import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.EntityMode;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
/**
* Settings that affect the behaviour of Hibernate at runtime.
@ -67,6 +68,8 @@ public final class Settings {
private boolean dataDefinitionInTransactionSupported;
private boolean strictJPAQLCompliance;
private boolean namedQueryStartupCheckingEnabled;
private EntityTuplizerFactory entityTuplizerFactory;
// private ComponentTuplizerFactory componentTuplizerFactory; todo : HHH-3517 and HHH-1907
// private BytecodeProvider bytecodeProvider;
/**
@ -257,6 +260,14 @@ public final class Settings {
return namedQueryStartupCheckingEnabled;
}
public EntityTuplizerFactory getEntityTuplizerFactory() {
return entityTuplizerFactory;
}
// public ComponentTuplizerFactory getComponentTuplizerFactory() {
// return componentTuplizerFactory;
// }
// package protected setters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -440,6 +451,14 @@ public final class Settings {
this.namedQueryStartupCheckingEnabled = namedQueryStartupCheckingEnabled;
}
void setEntityTuplizerFactory(EntityTuplizerFactory entityTuplizerFactory) {
this.entityTuplizerFactory = entityTuplizerFactory;
}
// void setComponentTuplizerFactory(ComponentTuplizerFactory componentTuplizerFactory) {
// this.componentTuplizerFactory = componentTuplizerFactory;
// }
// public BytecodeProvider getBytecodeProvider() {
// return bytecodeProvider;

View File

@ -5,8 +5,6 @@ import org.hibernate.tuple.Tuplizer;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.util.ReflectHelper;
import java.util.Map;
import java.util.HashMap;
@ -23,7 +21,8 @@ import java.io.Serializable;
*/
class ComponentEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping implements Serializable {
private static final Class[] COMPONENT_TUP_CTOR_SIG = new Class[] { Component.class };
// todo : move this to SF per HHH-3517; also see HHH-1907 and ComponentMetamodel
private ComponentTuplizerFactory componentTuplizerFactory = new ComponentTuplizerFactory();
public ComponentEntityModeToTuplizerMapping(Component component) {
PersistentClass owner = component.getOwner();
@ -35,24 +34,24 @@ class ComponentEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping i
}
// Build the dynamic-map tuplizer...
Tuplizer dynamicMapTuplizer = null;
String tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
if ( tuplizerImpl == null ) {
dynamicMapTuplizer = new DynamicMapComponentTuplizer( component );
Tuplizer dynamicMapTuplizer;
String tuplizerClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
if ( tuplizerClassName == null ) {
dynamicMapTuplizer = componentTuplizerFactory.constructDefaultTuplizer( EntityMode.MAP, component );
}
else {
dynamicMapTuplizer = buildComponentTuplizer( tuplizerImpl, component );
dynamicMapTuplizer = componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
}
// then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available
tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
Tuplizer pojoTuplizer = null;
tuplizerClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
Tuplizer pojoTuplizer;
if ( owner.hasPojoRepresentation() && component.hasPojoRepresentation() ) {
if ( tuplizerImpl == null ) {
pojoTuplizer = new PojoComponentTuplizer( component );
if ( tuplizerClassName == null ) {
pojoTuplizer = componentTuplizerFactory.constructDefaultTuplizer( EntityMode.POJO, component );
}
else {
pojoTuplizer = buildComponentTuplizer( tuplizerImpl, component );
pojoTuplizer = componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
}
}
else {
@ -60,14 +59,14 @@ class ComponentEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping i
}
// then dom4j tuplizer, if dom4j representation is available
Tuplizer dom4jTuplizer = null;
tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
Tuplizer dom4jTuplizer;
tuplizerClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
if ( owner.hasDom4jRepresentation() ) {
if ( tuplizerImpl == null ) {
dom4jTuplizer = new Dom4jComponentTuplizer( component );
if ( tuplizerClassName == null ) {
dom4jTuplizer = componentTuplizerFactory.constructDefaultTuplizer( EntityMode.DOM4J, component );
}
else {
dom4jTuplizer = buildComponentTuplizer( tuplizerImpl, component );
dom4jTuplizer = componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
}
}
else {
@ -89,21 +88,12 @@ class ComponentEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping i
if ( !userSuppliedTuplizerImpls.isEmpty() ) {
Iterator itr = userSuppliedTuplizerImpls.entrySet().iterator();
while ( itr.hasNext() ) {
Map.Entry entry = ( Map.Entry ) itr.next();
EntityMode entityMode = ( EntityMode ) entry.getKey();
ComponentTuplizer tuplizer = buildComponentTuplizer( ( String ) entry.getValue(), component );
final Map.Entry entry = ( Map.Entry ) itr.next();
final EntityMode entityMode = ( EntityMode ) entry.getKey();
final String userTuplizerClassName = ( String ) entry.getValue();
ComponentTuplizer tuplizer = componentTuplizerFactory.constructTuplizer( userTuplizerClassName, component );
addTuplizer( entityMode, tuplizer );
}
}
}
private ComponentTuplizer buildComponentTuplizer(String tuplizerImpl, Component component) {
try {
Class implClass = ReflectHelper.classForName( tuplizerImpl );
return ( ComponentTuplizer ) implClass.getConstructor( COMPONENT_TUP_CTOR_SIG ).newInstance( new Object[] { component } );
}
catch( Throwable t ) {
throw new HibernateException( "Could not build tuplizer [" + tuplizerImpl + "]", t );
}
}
}

View File

@ -0,0 +1,160 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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.
*
* 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
*
*/
package org.hibernate.tuple.component;
import java.util.Map;
import java.lang.reflect.Constructor;
import java.io.Serializable;
import org.hibernate.util.FastHashMap;
import org.hibernate.util.ReflectHelper;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.mapping.Component;
/**
* A registry allowing users to define the default {@link ComponentTuplizer} class to use per {@link EntityMode}.
*
* @author Steve Ebersole
*/
public class ComponentTuplizerFactory implements Serializable {
private static final Class[] COMPONENT_TUP_CTOR_SIG = new Class[] { Component.class };
private Map defaultImplClassByMode = buildBaseMapping();
/**
* Method allowing registration of the tuplizer class to use as default for a particular entity-mode.
*
* @param entityMode The entity-mode for which to register the tuplizer class
* @param tuplizerClass The class to use as the default tuplizer for the given entity-mode.
*/
public void registerDefaultTuplizerClass(EntityMode entityMode, Class tuplizerClass) {
assert isComponentTuplizerImplementor( tuplizerClass )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] does not implement " + ComponentTuplizer.class.getName();
assert hasProperConstructor( tuplizerClass )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable";
defaultImplClassByMode.put( entityMode, tuplizerClass );
}
/**
* Construct an instance of the given tuplizer class.
*
* @param tuplizerClassName The name of the tuplizer class to instantiate
* @param metadata The metadata for the component.
*
* @return The instantiated tuplizer
*
* @throws HibernateException If class name cannot be resolved to a class reference, or if the
* {@link Constructor#newInstance} call fails.
*/
public ComponentTuplizer constructTuplizer(String tuplizerClassName, Component metadata) {
try {
Class tuplizerClass = ReflectHelper.classForName( tuplizerClassName );
return constructTuplizer( tuplizerClass, metadata );
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Could not locate specified tuplizer class [" + tuplizerClassName + "]" );
}
}
/**
* Construct an instance of the given tuplizer class.
*
* @param tuplizerClass The tuplizer class to instantiate
* @param metadata The metadata for the component.
*
* @return The instantiated tuplizer
*
* @throws HibernateException if the {@link java.lang.reflect.Constructor#newInstance} call fails.
*/
public ComponentTuplizer constructTuplizer(Class tuplizerClass, Component metadata) {
Constructor ctor = getProperConstructor( tuplizerClass );
assert ctor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]";
try {
return ( ComponentTuplizer ) ctor.newInstance( new Object[] { metadata } );
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to instantiate default tuplizer [" + tuplizerClass.getName() + "]", t );
}
}
/**
* Construct am instance of the default tuplizer for the given entity-mode.
*
* @param entityMode The entity mode for which to build a default tuplizer.
* @param metadata The metadata for the component.
*
* @return The instantiated tuplizer
*
* @throws HibernateException If no default tuplizer found for that entity-mode; may be re-thrown from
* {@link #constructTuplizer} too.
*/
public ComponentTuplizer constructDefaultTuplizer(EntityMode entityMode, Component metadata) {
Class tuplizerClass = ( Class ) defaultImplClassByMode.get( entityMode );
if ( tuplizerClass == null ) {
throw new HibernateException( "could not determine default tuplizer class to use [" + entityMode + "]" );
}
return constructTuplizer( tuplizerClass, metadata );
}
private boolean isComponentTuplizerImplementor(Class tuplizerClass) {
return ReflectHelper.implementsInterface( tuplizerClass, ComponentTuplizer.class );
}
private boolean hasProperConstructor(Class tuplizerClass) {
return getProperConstructor( tuplizerClass ) != null;
}
private Constructor getProperConstructor(Class clazz) {
Constructor ctor = null;
try {
ctor = clazz.getDeclaredConstructor( COMPONENT_TUP_CTOR_SIG );
if ( ! ReflectHelper.isPublic( ctor ) ) {
try {
// found a ctor, but it was not publicly accessible so try to request accessibility
ctor.setAccessible( true );
}
catch ( SecurityException e ) {
ctor = null;
}
}
}
catch ( NoSuchMethodException ignore ) {
}
return ctor;
}
private static Map buildBaseMapping() {
Map map = new FastHashMap();
map.put( EntityMode.POJO, PojoComponentTuplizer.class );
map.put( EntityMode.DOM4J, Dom4jComponentTuplizer.class );
map.put( EntityMode.MAP, DynamicMapComponentTuplizer.class );
return map;
}
}

View File

@ -4,8 +4,6 @@ import org.hibernate.tuple.EntityModeToTuplizerMapping;
import org.hibernate.tuple.Tuplizer;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.util.ReflectHelper;
import java.util.Iterator;
import java.util.Map;
@ -22,8 +20,6 @@ import java.io.Serializable;
*/
public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping implements Serializable {
private static final Class[] ENTITY_TUP_CTOR_SIG = new Class[] { EntityMetamodel.class, PersistentClass.class };
/**
* Instantiates a EntityEntityModeToTuplizerMapping based on the given
* entity mapping and metamodel definitions.
@ -32,6 +28,10 @@ public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMappi
* @param em The entity metamodel definition.
*/
public EntityEntityModeToTuplizerMapping(PersistentClass mappedEntity, EntityMetamodel em) {
final EntityTuplizerFactory entityTuplizerFactory = em.getSessionFactory()
.getSettings()
.getEntityTuplizerFactory();
// create our own copy of the user-supplied tuplizer impl map
Map userSuppliedTuplizerImpls = new HashMap();
if ( mappedEntity.getTuplizerMap() != null ) {
@ -39,24 +39,24 @@ public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMappi
}
// Build the dynamic-map tuplizer...
Tuplizer dynamicMapTuplizer = null;
String tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
if ( tuplizerImpl == null ) {
dynamicMapTuplizer = new DynamicMapEntityTuplizer( em, mappedEntity );
Tuplizer dynamicMapTuplizer;
String tuplizerImplClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
if ( tuplizerImplClassName == null ) {
dynamicMapTuplizer = entityTuplizerFactory.constructDefaultTuplizer( EntityMode.MAP, em, mappedEntity );
}
else {
dynamicMapTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
dynamicMapTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerImplClassName, em, mappedEntity );
}
// then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available
Tuplizer pojoTuplizer = null;
tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
Tuplizer pojoTuplizer;
tuplizerImplClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
if ( mappedEntity.hasPojoRepresentation() ) {
if ( tuplizerImpl == null ) {
pojoTuplizer = new PojoEntityTuplizer( em, mappedEntity );
if ( tuplizerImplClassName == null ) {
pojoTuplizer = entityTuplizerFactory.constructDefaultTuplizer( EntityMode.POJO, em, mappedEntity );
}
else {
pojoTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
pojoTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerImplClassName, em, mappedEntity );
}
}
else {
@ -64,14 +64,14 @@ public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMappi
}
// then dom4j tuplizer, if dom4j representation is available
Tuplizer dom4jTuplizer = null;
tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
Tuplizer dom4jTuplizer;
tuplizerImplClassName = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
if ( mappedEntity.hasDom4jRepresentation() ) {
if ( tuplizerImpl == null ) {
dom4jTuplizer = new Dom4jEntityTuplizer( em, mappedEntity );
if ( tuplizerImplClassName == null ) {
dom4jTuplizer = entityTuplizerFactory.constructDefaultTuplizer( EntityMode.DOM4J, em, mappedEntity );
}
else {
dom4jTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
dom4jTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerImplClassName, em, mappedEntity );
}
}
else {
@ -93,21 +93,12 @@ public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMappi
if ( !userSuppliedTuplizerImpls.isEmpty() ) {
Iterator itr = userSuppliedTuplizerImpls.entrySet().iterator();
while ( itr.hasNext() ) {
Map.Entry entry = ( Map.Entry ) itr.next();
EntityMode entityMode = ( EntityMode ) entry.getKey();
EntityTuplizer tuplizer = buildEntityTuplizer( ( String ) entry.getValue(), mappedEntity, em );
final Map.Entry entry = ( Map.Entry ) itr.next();
final EntityMode entityMode = ( EntityMode ) entry.getKey();
final String tuplizerClassName = ( String ) entry.getValue();
final EntityTuplizer tuplizer = entityTuplizerFactory.constructTuplizer( tuplizerClassName, em, mappedEntity );
addTuplizer( entityMode, tuplizer );
}
}
}
private static EntityTuplizer buildEntityTuplizer(String className, PersistentClass pc, EntityMetamodel em) {
try {
Class implClass = ReflectHelper.classForName( className );
return ( EntityTuplizer ) implClass.getConstructor( ENTITY_TUP_CTOR_SIG ).newInstance( new Object[] { em, pc } );
}
catch( Throwable t ) {
throw new HibernateException( "Could not build tuplizer [" + className + "]", t );
}
}
}

View File

@ -215,4 +215,4 @@ public interface EntityTuplizer extends Tuplizer {
* @throws HibernateException If we are unable to determine an entity-name within the inheritence hierarchy.
*/
public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory);
}
}

View File

@ -0,0 +1,173 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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.
*
* 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
*
*/
package org.hibernate.tuple.entity;
import java.util.Map;
import java.lang.reflect.Constructor;
import java.io.Serializable;
import org.hibernate.util.FastHashMap;
import org.hibernate.util.ReflectHelper;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.mapping.PersistentClass;
/**
* A registry allowing users to define the default {@link EntityTuplizer} class to use per {@link EntityMode}.
*
* @author Steve Ebersole
*/
public class EntityTuplizerFactory implements Serializable {
public static final Class[] ENTITY_TUP_CTOR_SIG = new Class[] { EntityMetamodel.class, PersistentClass.class };
private Map defaultImplClassByMode = buildBaseMapping();
/**
* Method allowing registration of the tuplizer class to use as default for a particular entity-mode.
*
* @param entityMode The entity-mode for which to register the tuplizer class
* @param tuplizerClass The class to use as the default tuplizer for the given entity-mode.
*/
public void registerDefaultTuplizerClass(EntityMode entityMode, Class tuplizerClass) {
assert isEntityTuplizerImplementor( tuplizerClass )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] does not implement " + EntityTuplizer.class.getName();
assert hasProperConstructor( tuplizerClass )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable";
defaultImplClassByMode.put( entityMode, tuplizerClass );
}
/**
* Construct an instance of the given tuplizer class.
*
* @param tuplizerClassName The name of the tuplizer class to instantiate
* @param metamodel The metadata for the entity.
* @param persistentClass The mapping info for the entity.
*
* @return The instantiated tuplizer
*
* @throws HibernateException If class name cannot be resolved to a class reference, or if the
* {@link Constructor#newInstance} call fails.
*/
public EntityTuplizer constructTuplizer(
String tuplizerClassName,
EntityMetamodel metamodel,
PersistentClass persistentClass) {
try {
Class tuplizerClass = ReflectHelper.classForName( tuplizerClassName );
return constructTuplizer( tuplizerClass, metamodel, persistentClass );
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Could not locate specified tuplizer class [" + tuplizerClassName + "]" );
}
}
/**
* Construct an instance of the given tuplizer class.
*
* @param tuplizerClass The tuplizer class to instantiate
* @param metamodel The metadata for the entity.
* @param persistentClass The mapping info for the entity.
*
* @return The instantiated tuplizer
*
* @throws HibernateException if the {@link Constructor#newInstance} call fails.
*/
public EntityTuplizer constructTuplizer(
Class tuplizerClass,
EntityMetamodel metamodel,
PersistentClass persistentClass) {
Constructor ctor = getProperConstructor( tuplizerClass );
assert ctor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]";
try {
return ( EntityTuplizer ) ctor.newInstance( new Object[] { metamodel, persistentClass } );
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to instantiate default tuplizer [" + tuplizerClass.getName() + "]", t );
}
}
/**
* Construct am instance of the default tuplizer for the given entity-mode.
*
* @param entityMode The entity mode for which to build a default tuplizer.
* @param metamodel The entity metadata.
* @param persistentClass The entity mapping info.
*
* @return The instantiated tuplizer
*
* @throws HibernateException If no default tuplizer found for that entity-mode; may be re-thrown from
* {@link #constructTuplizer} too.
*/
public EntityTuplizer constructDefaultTuplizer(
EntityMode entityMode,
EntityMetamodel metamodel,
PersistentClass persistentClass) {
Class tuplizerClass = ( Class ) defaultImplClassByMode.get( entityMode );
if ( tuplizerClass == null ) {
throw new HibernateException( "could not determine default tuplizer class to use [" + entityMode + "]" );
}
return constructTuplizer( tuplizerClass, metamodel, persistentClass );
}
private boolean isEntityTuplizerImplementor(Class tuplizerClass) {
return ReflectHelper.implementsInterface( tuplizerClass, EntityTuplizer.class );
}
private boolean hasProperConstructor(Class tuplizerClass) {
return getProperConstructor( tuplizerClass ) != null;
}
private Constructor getProperConstructor(Class clazz) {
Constructor ctor = null;
try {
ctor = clazz.getDeclaredConstructor( ENTITY_TUP_CTOR_SIG );
if ( ! ReflectHelper.isPublic( ctor ) ) {
try {
// found a ctor, but it was not publicly accessible so try to request accessibility
ctor.setAccessible( true );
}
catch ( SecurityException e ) {
ctor = null;
}
}
}
catch ( NoSuchMethodException ignore ) {
}
return ctor;
}
private static Map buildBaseMapping() {
Map map = new FastHashMap();
map.put( EntityMode.POJO, PojoEntityTuplizer.class );
map.put( EntityMode.DOM4J, Dom4jEntityTuplizer.class );
map.put( EntityMode.MAP, DynamicMapEntityTuplizer.class );
return map;
}
}

View File

@ -16,90 +16,132 @@ import org.hibernate.property.PropertyAccessor;
import org.hibernate.type.PrimitiveType;
import org.hibernate.type.Type;
/**
* Utility class for various reflection operations.
*
* @author Gavin King
* @author Steve Ebersole
*/
public final class ReflectHelper {
//TODO: this dependency is kinda Bad
private static final PropertyAccessor BASIC_PROPERTY_ACCESSOR = new BasicPropertyAccessor();
private static final PropertyAccessor DIRECT_PROPERTY_ACCESSOR = new DirectPropertyAccessor();
private static final Class[] NO_CLASSES = new Class[0];
private static final Class[] OBJECT = new Class[] { Object.class };
private static final Method OBJECT_EQUALS;
private static final Class[] NO_PARAM = new Class[] { };
public static final Class[] NO_PARAM_SIGNATURE = new Class[0];
public static final Object[] NO_PARAMS = new Object[0];
public static final Class[] SINGLE_OBJECT_PARAM_SIGNATURE = new Class[] { Object.class };
private static final Method OBJECT_EQUALS;
private static final Method OBJECT_HASHCODE;
static {
Method eq;
Method hash;
try {
eq = Object.class.getMethod("equals", OBJECT);
hash = Object.class.getMethod("hashCode", NO_PARAM);
eq = extractEqualsMethod( Object.class );
hash = extractHashCodeMethod( Object.class );
}
catch (Exception e) {
throw new AssertionFailure("Could not find Object.equals() or Object.hashCode()", e);
catch ( Exception e ) {
throw new AssertionFailure( "Could not find Object.equals() or Object.hashCode()", e );
}
OBJECT_EQUALS = eq;
OBJECT_HASHCODE = hash;
}
/**
* Disallow instantiation of ReflectHelper.
*/
private ReflectHelper() {
}
/**
* Encapsulation of getting hold of a class's {@link Object#equals equals} method.
*
* @param clazz The class from which to extract the equals method.
* @return The equals method reference
* @throws NoSuchMethodException Should indicate an attempt to extract equals method from interface.
*/
public static Method extractEqualsMethod(Class clazz) throws NoSuchMethodException {
return clazz.getMethod( "equals", SINGLE_OBJECT_PARAM_SIGNATURE );
}
/**
* Encapsulation of getting hold of a class's {@link Object#hashCode hashCode} method.
*
* @param clazz The class from which to extract the hashCode method.
* @return The hashCode method reference
* @throws NoSuchMethodException Should indicate an attempt to extract hashCode method from interface.
*/
public static Method extractHashCodeMethod(Class clazz) throws NoSuchMethodException {
return clazz.getMethod( "hashCode", NO_PARAM_SIGNATURE );
}
/**
* Determine if the given class defines an {@link Object#equals} override.
*
* @param clazz The class to check
* @return True if clazz defines an equals override.
*/
public static boolean overridesEquals(Class clazz) {
Method equals;
try {
equals = clazz.getMethod("equals", OBJECT);
equals = extractEqualsMethod( clazz );
}
catch (NoSuchMethodException nsme) {
catch ( NoSuchMethodException nsme ) {
return false; //its an interface so we can't really tell anything...
}
return !OBJECT_EQUALS.equals(equals);
return !OBJECT_EQUALS.equals( equals );
}
/**
* Determine if the given class defines a {@link Object#hashCode} override.
*
* @param clazz The class to check
* @return True if clazz defines an hashCode override.
*/
public static boolean overridesHashCode(Class clazz) {
Method hashCode;
try {
hashCode = clazz.getMethod("hashCode", NO_PARAM);
hashCode = extractHashCodeMethod( clazz );
}
catch (NoSuchMethodException nsme) {
catch ( NoSuchMethodException nsme ) {
return false; //its an interface so we can't really tell anything...
}
return !OBJECT_HASHCODE.equals(hashCode);
return !OBJECT_HASHCODE.equals( hashCode );
}
public static Class reflectedPropertyClass(String className, String name) throws MappingException {
try {
Class clazz = ReflectHelper.classForName(className);
return getter(clazz, name).getReturnType();
}
catch (ClassNotFoundException cnfe) {
throw new MappingException("class " + className + " not found while looking for property: " + name, cnfe);
}
}
/**
* Determine if the given class implements the given interface.
*
* @param clazz The class to check
* @param intf The interface to check it against.
* @return True if the class does implement the interface, false otherwise.
*/
public static boolean implementsInterface(Class clazz, Class intf) {
assert intf.isInterface() : "Interface to check was not an interface";
private static Getter getter(Class clazz, String name) throws MappingException {
try {
return BASIC_PROPERTY_ACCESSOR.getGetter(clazz, name);
}
catch (PropertyNotFoundException pnfe) {
return DIRECT_PROPERTY_ACCESSOR.getGetter(clazz, name);
}
}
public static Getter getGetter(Class theClass, String name) throws MappingException {
return BASIC_PROPERTY_ACCESSOR.getGetter(theClass, name);
}
public static Class classForName(String name) throws ClassNotFoundException {
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if ( contextClassLoader != null ) {
return contextClassLoader.loadClass(name);
Class[] interfaces = clazz.getInterfaces();
for ( int i = 0; i < interfaces.length; i++ ) {
if ( intf.isAssignableFrom( interfaces[i] ) ) {
return true;
}
}
catch ( Throwable t ) {
}
return Class.forName( name );
return false;
}
/**
* Perform resolution of a class name.
* <p/>
* Here we first check the context classloader, if one, before delegating to
* {@link Class#forName(String, boolean, ClassLoader)} using the caller's classloader
*
* @param name The class name
* @param caller The class from which this call originated (in order to access that class's loader).
* @return The class reference.
* @throws ClassNotFoundException From {@link Class#forName(String, boolean, ClassLoader)}.
*/
public static Class classForName(String name, Class caller) throws ClassNotFoundException {
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
@ -107,15 +149,101 @@ public final class ReflectHelper {
return contextClassLoader.loadClass( name );
}
}
catch ( Throwable e ) {
catch ( Throwable ignore ) {
}
return Class.forName( name, true, caller.getClassLoader() );
}
/**
* Perform resolution of a class name.
* <p/>
* Same as {@link #classForName(String, Class)} except that here we delegate to
* {@link Class#forName(String)} if the context classloader lookup is unsuccessful.
*
* @param name The class name
* @return The class reference.
* @throws ClassNotFoundException From {@link Class#forName(String)}.
*/
public static Class classForName(String name) throws ClassNotFoundException {
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if ( contextClassLoader != null ) {
return contextClassLoader.loadClass(name);
}
}
catch ( Throwable ignore ) {
}
return Class.forName( name );
}
/**
* Is this member publicly accessible.
* <p/>
* Short-hand for {@link #isPublic(Class, Member)} passing the member + {@link Member#getDeclaringClass()}
*
* @param member The member to check
* @return True if the member is publicly accessible.
*/
public static boolean isPublic(Member member) {
return isPublic( member.getDeclaringClass(), member );
}
/**
* Is this member publicly accessible.
*
* @param clazz The class which defines the member
* @param member The memeber.
* @return True if the member is publicly accessible, false otherwise.
*/
public static boolean isPublic(Class clazz, Member member) {
return Modifier.isPublic( member.getModifiers() ) && Modifier.isPublic( clazz.getModifiers() );
}
/**
* Attempt to resolve the specified property type through reflection.
*
* @param className The name of the class owning the property.
* @param name The name of the property.
* @return The type of the property.
* @throws MappingException Indicates we were unable to locate the property.
*/
public static Class reflectedPropertyClass(String className, String name) throws MappingException {
try {
Class clazz = ReflectHelper.classForName( className );
return getter( clazz, name ).getReturnType();
}
catch ( ClassNotFoundException cnfe ) {
throw new MappingException( "class " + className + " not found while looking for property: " + name, cnfe );
}
}
private static Getter getter(Class clazz, String name) throws MappingException {
try {
return BASIC_PROPERTY_ACCESSOR.getGetter( clazz, name );
}
catch ( PropertyNotFoundException pnfe ) {
return DIRECT_PROPERTY_ACCESSOR.getGetter( clazz, name );
}
}
/**
* Directly retrieve the {@link Getter} reference via the {@link BasicPropertyAccessor}.
*
* @param theClass The class owning the property
* @param name The name of the property
* @return The getter.
* @throws MappingException Indicates we were unable to locate the property.
*/
public static Getter getGetter(Class theClass, String name) throws MappingException {
return BASIC_PROPERTY_ACCESSOR.getGetter( theClass, name );
}
/**
* Resolve a constant to its actual value.
*
* @param name The name
* @return The value
*/
public static Object getConstantValue(String name) {
Class clazz;
try {
@ -125,61 +253,90 @@ public final class ReflectHelper {
return null;
}
try {
return clazz.getField( StringHelper.unqualify( name ) ).get(null);
return clazz.getField( StringHelper.unqualify( name ) ).get( null );
}
catch ( Throwable t ) {
return null;
}
}
/**
* Retrieve the default (no arg) constructor from the given class.
*
* @param clazz The class for which to retrieve the default ctor.
* @return The default constructor.
* @throws PropertyNotFoundException Indicates there was not publicly accessible, no-arg constructor (todo : why PropertyNotFoundException???)
*/
public static Constructor getDefaultConstructor(Class clazz) throws PropertyNotFoundException {
if ( isAbstractClass(clazz) ) return null;
if ( isAbstractClass( clazz ) ) {
return null;
}
try {
Constructor constructor = clazz.getDeclaredConstructor(NO_CLASSES);
if ( !isPublic(clazz, constructor) ) {
constructor.setAccessible(true);
Constructor constructor = clazz.getDeclaredConstructor( NO_PARAM_SIGNATURE );
if ( !isPublic( clazz, constructor ) ) {
constructor.setAccessible( true );
}
return constructor;
}
catch (NoSuchMethodException nme) {
catch ( NoSuchMethodException nme ) {
throw new PropertyNotFoundException(
"Object class " + clazz.getName() +
" must declare a default (no-argument) constructor"
"Object class [" + clazz.getName() + "] must declare a default (no-argument) constructor"
);
}
}
/**
* Determine if the given class is declared abstract.
*
* @param clazz The class to check.
* @return True if the class is abstract, false otherwise.
*/
public static boolean isAbstractClass(Class clazz) {
int modifier = clazz.getModifiers();
return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier);
}
/**
* Determine is the given class is declared final.
*
* @param clazz The class to check.
* @return True if the class is final, flase otherwise.
*/
public static boolean isFinalClass(Class clazz) {
return Modifier.isFinal( clazz.getModifiers() );
}
/**
* Retrieve a constructor for the given class, with arguments matching the specified Hibernate mapping
* {@link Type types}.
*
* @param clazz The class needing instantiation
* @param types The types representing the required ctor param signature
* @return The matching constructor.
* @throws PropertyNotFoundException Indicates we could not locate an appropriate constructor (todo : again with PropertyNotFoundException???)
*/
public static Constructor getConstructor(Class clazz, Type[] types) throws PropertyNotFoundException {
final Constructor[] candidates = clazz.getConstructors();
for ( int i=0; i<candidates.length; i++ ) {
for ( int i = 0; i < candidates.length; i++ ) {
final Constructor constructor = candidates[i];
final Class[] params = constructor.getParameterTypes();
if ( params.length==types.length ) {
if ( params.length == types.length ) {
boolean found = true;
for ( int j=0; j<params.length; j++ ) {
for ( int j = 0; j < params.length; j++ ) {
final boolean ok = params[j].isAssignableFrom( types[j].getReturnedClass() ) || (
types[j] instanceof PrimitiveType &&
params[j] == ( (PrimitiveType) types[j] ).getPrimitiveClass()
types[j] instanceof PrimitiveType &&
params[j] == ( ( PrimitiveType ) types[j] ).getPrimitiveClass()
);
if (!ok) {
if ( !ok ) {
found = false;
break;
}
}
if (found) {
if ( !isPublic(clazz, constructor) ) constructor.setAccessible(true);
if ( found ) {
if ( !isPublic( clazz, constructor ) ) {
constructor.setAccessible( true );
}
return constructor;
}
}
@ -196,6 +353,4 @@ public final class ReflectHelper {
}
}
private ReflectHelper() {}
}

View File

@ -31,7 +31,6 @@
<hibernate-mapping package="org.hibernate.test.dynamicentity">
<class name="Person" table="t_person" discriminator-value="person" abstract="false">
<tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
<id name="id">
<generator class="native"/>
</id>
@ -46,13 +45,11 @@
</set>
<subclass name="Customer" discriminator-value="customer" abstract="false">
<tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
<many-to-one name="company" cascade="none" column="comp_id"/>
</subclass>
</class>
<class name="Company" table="t_company" abstract="false">
<tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
<id name="id">
<generator class="native"/>
</id>
@ -60,7 +57,6 @@
</class>
<class name="Address" table="t_address" abstract="false">
<tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
<id name="id">
<generator class="native"/>
</id>

View File

@ -31,6 +31,7 @@ import org.hibernate.test.dynamicentity.Address;
import org.hibernate.test.dynamicentity.Person;
import org.hibernate.Session;
import org.hibernate.Hibernate;
import org.hibernate.EntityMode;
import org.hibernate.cfg.Configuration;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
@ -61,6 +62,7 @@ public class ImprovedTuplizerDynamicEntityTest extends FunctionalTestCase {
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.getEntityTuplizerFactory().registerDefaultTuplizerClass( EntityMode.POJO, MyEntityTuplizer.class );
}
public static TestSuite suite() {