HHH-6569 : Update persisters and tuplizers to use components

This commit is contained in:
Gail Badner 2012-07-19 13:25:48 -07:00
parent 42a3061f3e
commit ba459aa00c
21 changed files with 543 additions and 134 deletions

View File

@ -50,6 +50,7 @@ import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.metamodel.internal.HibernateTypeHelper.ReflectedCollectionJavaTypes;
import org.hibernate.metamodel.internal.source.hbm.ListAttributeSource;
import org.hibernate.metamodel.internal.source.hbm.MapAttributeSource;
@ -148,6 +149,7 @@ import org.hibernate.metamodel.spi.source.VersionAttributeSource;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.config.spi.ConfigurationService;
import org.hibernate.tuple.component.ComponentMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
@ -210,6 +212,12 @@ public class Binder {
}
}
private SingularAttributeBinding bindIdentifierAttribute(
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeSource attributeSource) {
return bindSingularAttribute( attributeBindingContainer, attributeSource, true );
}
private AttributeBinding bindAttribute(
final AttributeBindingContainer attributeBindingContainer,
final AttributeSource attributeSource) {
@ -220,15 +228,20 @@ public class Binder {
return attributeBinding;
}
return attributeSource.isSingular() ?
bindSingularAttribute(attributeBindingContainer,SingularAttributeSource.class.cast( attributeSource ))
: bindPluralAttribute( attributeBindingContainer,PluralAttributeSource.class.cast( attributeSource ) );
bindSingularAttribute(
attributeBindingContainer,
SingularAttributeSource.class.cast( attributeSource ),
false
) :
bindPluralAttribute( attributeBindingContainer,PluralAttributeSource.class.cast( attributeSource ) );
}
// Singular attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private SingularAttributeBinding bindSingularAttribute(
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeSource attributeSource ) {
final SingularAttributeSource attributeSource,
boolean isIdentifierAttribute) {
final SingularAttributeNature nature = attributeSource.getNature();
final SingularAttribute attribute =
attributeBindingContainer.getAttributeContainer().locateSingularAttribute( attributeSource.getName() );
@ -245,7 +258,8 @@ public class Binder {
return bindComponentAttribute(
attributeBindingContainer,
ComponentAttributeSource.class.cast( attributeSource ),
attribute
attribute,
isIdentifierAttribute
);
default:
throw new NotYetImplementedException( nature.toString() );
@ -290,27 +304,46 @@ public class Binder {
private CompositeAttributeBinding bindComponentAttribute(
final AttributeBindingContainer attributeBindingContainer,
final ComponentAttributeSource attributeSource,
SingularAttribute attribute ) {
SingularAttribute attribute,
boolean isAttributeIdentifier) {
final Composite composite;
ValueHolder<Class<?>> defaultJavaClassReference = null;
if ( attribute == null ) {
composite = new Composite(
attributeSource.getPath(),
attributeSource.getClassName(),
attributeSource.getClassReference(),
null );
if ( attributeSource.getClassName() != null ) {
composite = new Composite(
attributeSource.getPath(),
attributeSource.getClassName(),
attributeSource.getClassReference() != null ?
attributeSource.getClassReference() :
bindingContext().makeClassReference( attributeSource.getClassName() ),
null
);
// no need for a default because there's an explicit class name provided
}
else {
defaultJavaClassReference = createSingularAttributeJavaType(
attributeBindingContainer.getClassReference(), attributeSource.getName()
);
composite = new Composite(
attributeSource.getPath(),
defaultJavaClassReference.getValue().getName(),
defaultJavaClassReference,
null
);
}
attribute = attributeBindingContainer.getAttributeContainer().createCompositeAttribute(
attributeSource.getName(),
composite );
} else {
composite = ( Composite ) attribute.getSingularAttributeType();
attributeSource.getName(),
composite
);
}
else {
composite = (Composite) attribute.getSingularAttributeType();
}
final SingularAttribute referencingAttribute;
if ( StringHelper.isEmpty( attributeSource.getParentReferenceAttributeName() ) ) {
referencingAttribute = null;
} else {
referencingAttribute = composite.createSingularAttribute( attributeSource.getParentReferenceAttributeName() );
}
final SingularAttribute referencingAttribute =
StringHelper.isEmpty( attributeSource.getParentReferenceAttributeName() ) ?
null :
composite.createSingularAttribute( attributeSource.getParentReferenceAttributeName() );
final SingularAttributeBinding.NaturalIdMutability naturalIdMutability = attributeSource.getNaturalIdMutability();
final CompositeAttributeBinding attributeBinding =
attributeBindingContainer.makeComponentAttributeBinding(
@ -321,7 +354,28 @@ public class Binder {
attributeSource.isLazy(),
naturalIdMutability,
createMetaAttributeContext( attributeBindingContainer, attributeSource ) );
bindAttributes( attributeBinding, attributeSource );
// TODO: binding the HibernateTypeDescriptor should be simplified since we know the class name already
bindHibernateTypeDescriptor(
attributeBinding.getHibernateTypeDescriptor(),
composite.getClassName(),
null,
defaultJavaClassReference == null ? null : defaultJavaClassReference.getValue().getName()
);
if ( referencingAttribute == null ) {
bindAttributes( attributeBinding, attributeSource );
}
else {
for ( final AttributeSource subAttributeSource : attributeSource.attributeSources() ) {
// TODO: don't create a "parent" attribute binding???
if ( ! subAttributeSource.getName().equals( referencingAttribute.getName() ) ) {
bindAttribute( attributeBinding, subAttributeSource );
}
}
}
Type resolvedType = metadata.getTypeResolver().getTypeFactory().component(
new ComponentMetamodel( attributeBinding, isAttributeIdentifier )
);
bindHibernateResolvedType( attributeBinding.getHibernateTypeDescriptor(), resolvedType );
return attributeBinding;
}
@ -1040,6 +1094,8 @@ public class Binder {
}
}
// TODO: simplify how HibernateTypeDescriptor is bound
private void bindHibernateTypeDescriptor(
final HibernateTypeDescriptor hibernateTypeDescriptor,
final ExplicitHibernateTypeSource explicitTypeSource,
@ -1047,7 +1103,9 @@ public class Binder {
// if there is an explicit type name specified, then there's no reason to
// initialize the default Java type name; simply pass a null default instead.
bindHibernateTypeDescriptor(
hibernateTypeDescriptor, explicitTypeSource, explicitTypeSource.getName() == null
hibernateTypeDescriptor,
explicitTypeSource,
explicitTypeSource == null || explicitTypeSource.getName() == null
? defaultJavaType.getValue().getName()
: null
);
@ -1131,8 +1189,9 @@ public class Binder {
private void bindSimpleIdentifier( final EntityBinding rootEntityBinding, final SimpleIdentifierSource identifierSource ) {
// locate the attribute binding
final BasicAttributeBinding idAttributeBinding =
( BasicAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
final BasicAttributeBinding idAttributeBinding = ( BasicAttributeBinding ) bindIdentifierAttribute(
rootEntityBinding, identifierSource.getIdentifierAttributeSource()
);
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
@ -1155,8 +1214,9 @@ public class Binder {
EntityBinding rootEntityBinding,
AggregatedCompositeIdentifierSource identifierSource ) {
// locate the attribute binding
final CompositeAttributeBinding idAttributeBinding =
( CompositeAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
final CompositeAttributeBinding idAttributeBinding = ( CompositeAttributeBinding ) bindIdentifierAttribute(
rootEntityBinding, identifierSource.getIdentifierAttributeSource()
);
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
@ -1181,7 +1241,7 @@ public class Binder {
// locate the attribute bindings for the real attributes
List< SingularAttributeBinding > idAttributeBindings = new ArrayList< SingularAttributeBinding >();
for ( SingularAttributeSource attributeSource : identifierSource.getAttributeSourcesMakingUpIdentifier() ) {
idAttributeBindings.add( ( SingularAttributeBinding ) bindAttribute( rootEntityBinding, attributeSource ) );
idAttributeBindings.add( bindIdentifierAttribute( rootEntityBinding, attributeSource ) );
}
// Create the synthetic attribute
@ -1571,7 +1631,10 @@ public class Binder {
if(isNaturalId){
addUniqueConstraintForNaturalIdColumn( defaultTable, column );
}
valueBindings.add( new RelationalValueBinding( column, true, !isImmutableNaturalId ) );
valueBindings.add( new RelationalValueBinding(
column,
valueSourceContainer.areValuesIncludedInInsertByDefault(),
valueSourceContainer.areValuesIncludedInUpdateByDefault() && !isImmutableNaturalId ) );
} else {
final String name = attribute.getName();
for ( final RelationalValueSource valueSource : valueSourceContainer.relationalValueSources() ) {
@ -2074,17 +2137,27 @@ public class Binder {
private static org.hibernate.internal.util.ValueHolder< Class< ? >> createSingularAttributeJavaType(
final SingularAttribute attribute ) {
return createSingularAttributeJavaType(
attribute.getAttributeContainer().getClassReference(),
attribute.getName()
);
}
private static org.hibernate.internal.util.ValueHolder< Class< ? >> createSingularAttributeJavaType(
final Class< ? > attributeContainerClassReference,
final String attributeName ) {
org.hibernate.internal.util.ValueHolder.DeferredInitializer< Class< ? >> deferredInitializer =
new org.hibernate.internal.util.ValueHolder.DeferredInitializer< Class< ? >>() {
public Class< ? > initialize() {
return ReflectHelper.reflectedPropertyClass(
attribute.getAttributeContainer().getClassReference(),
attribute.getName() );
attributeContainerClassReference,
attributeName );
}
};
return new org.hibernate.internal.util.ValueHolder< Class< ? >>( deferredInitializer );
}
private static String interpretIdentifierUnsavedValue( IdentifierSource identifierSource, IdGenerator generator ) {
if ( identifierSource == null ) {
throw new IllegalArgumentException( "identifierSource must be non-null." );

View File

@ -117,7 +117,8 @@ class ColumnSourceImpl
@Override
public boolean isUnique() {
return columnElement.isUnique();
// TODO: should TruthValue be returned instead of boolean?
return columnElement.isUnique() != null && columnElement.isUnique().booleanValue();
}
@Override

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -116,7 +117,7 @@ public class CompositeAttributeBinding
this.path = container.getPathBase() + '.' + attribute.getName();
if ( subAttributeBindings == null ) {
attributeBindingMap = new HashMap<String, AttributeBinding>();
attributeBindingMap = new LinkedHashMap<String, AttributeBinding>();
}
else {
HashMap<String, AttributeBinding> map = new HashMap<String, AttributeBinding>();
@ -175,8 +176,15 @@ public class CompositeAttributeBinding
@Override
public boolean isNullable() {
// todo : not sure this is even relevant for components
return false;
// return false if there are any singular attributes are non-nullable
for ( AttributeBinding attributeBinding : attributeBindings() ) {
// only check singular attributes
if ( attributeBinding.getAttribute().isSingular() &&
! ( (SingularAttributeBinding) attributeBinding ).isNullable() ) {
return false;
}
}
return true;
}
@Override
@ -205,6 +213,10 @@ public class CompositeAttributeBinding
return null;
}
public int attributeBindingSpan() {
return attributeBindingMap.size();
}
@Override
public Iterable<AttributeBinding> attributeBindings() {
return attributeBindingMap.values();

View File

@ -96,22 +96,30 @@ public final class PropertyAccessorFactory {
* @throws MappingException
*/
public static PropertyAccessor getPropertyAccessor(AttributeBinding property, EntityMode mode) throws MappingException {
//TODO: this is temporary in that the end result will probably not take a Property reference per-se.
if ( property.isBackRef() ) {
BackRefAttributeBinding backRefAttributeBinding = (BackRefAttributeBinding) property;
return new BackrefPropertyAccessor(
backRefAttributeBinding.getCollectionRole(), backRefAttributeBinding.getEntityName()
);
if ( null == mode || EntityMode.POJO.equals( mode ) ) {
if ( property.isBackRef() ) {
//TODO: this is temporary in that the end result will probably not take a Property reference per-se.
BackRefAttributeBinding backRefAttributeBinding = (BackRefAttributeBinding) property;
return new BackrefPropertyAccessor(
backRefAttributeBinding.getCollectionRole(), backRefAttributeBinding.getEntityName()
);
}
else {
return getPojoPropertyAccessor( property.getPropertyAccessorName() );
}
}
else if (EntityMode.MAP.equals( mode ) ) {
if ( property.isBackRef() ) {
//TODO: this is temporary in that the end result will probably not take a Property reference per-se.
return PropertyAccessorFactory.getPropertyAccessor( null, property.getPropertyAccessorName() );
}
else {
return getDynamicMapPropertyAccessor();
}
}
else {
throw new MappingException( "Unknown entity mode [" + mode + "]" );
}
else if ( null == mode || EntityMode.POJO.equals( mode ) ) {
return getPojoPropertyAccessor( property.getPropertyAccessorName() );
}
else if ( EntityMode.MAP.equals( mode ) ) {
return getDynamicMapPropertyAccessor();
}
else {
throw new MappingException( "Unknown entity mode [" + mode + "]" );
}
}
/**

View File

@ -37,6 +37,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
/**
@ -71,6 +72,23 @@ public class PojoInstantiator implements Instantiator, Serializable {
}
}
public PojoInstantiator(CompositeAttributeBinding component, ReflectionOptimizer.InstantiationOptimizer optimizer) {
this.mappedClass = component.getClassReference();
this.isAbstract = ReflectHelper.isAbstractClass( mappedClass );
this.optimizer = optimizer;
this.proxyInterface = null;
this.embeddedIdentifier = false;
try {
constructor = ReflectHelper.getDefaultConstructor(mappedClass);
}
catch ( PropertyNotFoundException pnfe ) {
LOG.noDefaultConstructor(mappedClass.getName());
constructor = null;
}
}
public PojoInstantiator(PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) {
this.mappedClass = persistentClass.getMappedClass();
this.isAbstract = ReflectHelper.isAbstractClass( mappedClass );

View File

@ -27,6 +27,7 @@ import java.lang.reflect.Constructor;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.engine.internal.UnsavedValueFactory;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.IdentifierValue;
@ -48,6 +49,7 @@ import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
@ -122,7 +124,7 @@ public class PropertyFactory {
IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
mappedUnsavedValue,
getGetter( property ),
getGetterOrNull( property ),
type,
getConstructor( mappedEntity )
);
@ -201,7 +203,7 @@ public class PropertyFactory {
final String mappedUnsavedValue = entityBinding.getHierarchyDetails().getEntityVersion().getUnsavedValue();
final VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
mappedUnsavedValue,
getGetter( property ),
getGetterOrNull( property ),
(VersionType) property.getHibernateTypeDescriptor().getResolvedTypeMapping(),
getConstructor( (EntityBinding) property.getContainer() )
);
@ -307,13 +309,13 @@ public class PropertyFactory {
null,
type,
lazyAvailable && singularAttributeBinding.isLazy(),
true, // insertable
true, // updatable
areAnyValuesIncludedInInsert( singularAttributeBinding ), // insertable
areAnyValuesIncludedInUpdate( singularAttributeBinding ), // updatable
propertyGeneration == PropertyGeneration.INSERT
|| propertyGeneration == PropertyGeneration.ALWAYS,
propertyGeneration == PropertyGeneration.ALWAYS,
singularAttributeBinding.isNullable(),
alwaysDirtyCheck || areAllValuesIncludedInUpdate( singularAttributeBinding ),
alwaysDirtyCheck || areAnyValuesIncludedInUpdate( singularAttributeBinding ),
singularAttributeBinding.isIncludedInOptimisticLocking(),
cascadeStyle,
fetchMode
@ -349,16 +351,22 @@ public class PropertyFactory {
}
}
private static boolean areAllValuesIncludedInUpdate(SingularAttributeBinding attributeBinding) {
if ( attributeBinding.hasDerivedValue() ) {
return false;
}
private static boolean areAnyValuesIncludedInInsert(SingularAttributeBinding attributeBinding) {
for ( RelationalValueBinding valueBinding : attributeBinding.getRelationalValueBindings() ) {
if ( ! valueBinding.isIncludeInUpdate() ) {
return false;
if ( valueBinding.isIncludeInInsert() ) {
return true;
}
}
return true;
return false;
}
private static boolean areAnyValuesIncludedInUpdate(SingularAttributeBinding attributeBinding) {
for ( RelationalValueBinding valueBinding : attributeBinding.getRelationalValueBindings() ) {
if ( valueBinding.isIncludeInUpdate() ) {
return true;
}
}
return false;
}
private static Constructor getConstructor(PersistentClass persistentClass) {
@ -396,17 +404,36 @@ public class PropertyFactory {
return pa.getGetter( mappingProperty.getPersistentClass().getMappedClass(), mappingProperty.getName() );
}
private static Getter getGetter(AttributeBinding mappingProperty) {
if ( mappingProperty == null || mappingProperty.getContainer().getClassReference() == null ) {
return null;
}
PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( mappingProperty, EntityMode.POJO );
return pa.getGetter(
public static Getter getGetter(AttributeBinding mappingProperty) {
return getPropertyAccessor( mappingProperty ).getGetter(
mappingProperty.getContainer().getClassReference(),
mappingProperty.getAttribute().getName()
);
}
private static Getter getGetterOrNull(AttributeBinding mappingProperty) {
try {
return getGetter( mappingProperty );
}
catch ( PropertyNotFoundException ex ) {
// ignore exception
}
return null;
}
public static Setter getSetter(AttributeBinding mappingProperty) {
return getPropertyAccessor( mappingProperty ).getSetter(
mappingProperty.getContainer().getClassReference(),
mappingProperty.getAttribute().getName()
);
}
private static PropertyAccessor getPropertyAccessor(AttributeBinding mappingProperty) {
// TODO: fix this to work w/ component entity mode also
return PropertyAccessorFactory.getPropertyAccessor(
mappingProperty,
mappingProperty.getContainer().seekEntityBinding().getHierarchyDetails().getEntityMode()
);
}
}

View File

@ -30,9 +30,12 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PropertyFactory;
/**
* Support for tuplizers relating to components.
@ -51,6 +54,8 @@ public abstract class AbstractComponentTuplizer implements ComponentTuplizer {
protected abstract Getter buildGetter(Component component, Property prop);
protected abstract Setter buildSetter(Component component, Property prop);
protected abstract Instantiator buildInstantiator(CompositeAttributeBinding component);
protected AbstractComponentTuplizer(Component component) {
propertySpan = component.getPropertySpan();
getters = new Getter[propertySpan];
@ -72,6 +77,25 @@ public abstract class AbstractComponentTuplizer implements ComponentTuplizer {
instantiator = buildInstantiator( component );
}
protected AbstractComponentTuplizer(CompositeAttributeBinding component) {
propertySpan = component.attributeBindingSpan();
getters = new Getter[propertySpan];
setters = new Setter[propertySpan];
boolean foundCustomAccessor=false;
int i = 0;
for ( AttributeBinding attributeBinding : component.attributeBindings() ) {
getters[i] = PropertyFactory.getGetter( attributeBinding );
setters[i] = PropertyFactory.getSetter( attributeBinding );
if ( !attributeBinding.isBasicPropertyAccessor() ) {
foundCustomAccessor = true;
}
i++;
}
hasCustomAccessors = foundCustomAccessor;
instantiator = buildInstantiator( component );
}
public Object getPropertyValue(Object component, int i) throws HibernateException {
return getters[i].get( component );
}

View File

@ -32,6 +32,8 @@ import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.StandardProperty;
@ -45,7 +47,6 @@ public class ComponentMetamodel implements Serializable {
// TODO : will need reference to session factory to fully complete HHH-1907
// private final SessionFactoryImplementor sessionFactory;
private final String role;
private final boolean isKey;
private final StandardProperty[] properties;
@ -54,12 +55,11 @@ public class ComponentMetamodel implements Serializable {
// cached for efficiency...
private final int propertySpan;
private final Map propertyIndexes = new HashMap();
private final Map<String,Integer> propertyIndexes = new HashMap<String,Integer>();
// public ComponentMetamodel(Component component, SessionFactoryImplementor sessionFactory) {
public ComponentMetamodel(Component component) {
// this.sessionFactory = sessionFactory;
this.role = component.getRoleName();
this.isKey = component.isKey();
propertySpan = component.getPropertySpan();
properties = new StandardProperty[propertySpan];
@ -83,6 +83,31 @@ public class ComponentMetamodel implements Serializable {
) : componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
}
public ComponentMetamodel(CompositeAttributeBinding component, boolean isIdentifierAttributeBinding) {
this.isKey = isIdentifierAttributeBinding;
propertySpan = component.attributeBindingSpan();
properties = new StandardProperty[propertySpan];
int i = 0;
for ( AttributeBinding attributeBinding : component.attributeBindings() ) {
properties[i] = PropertyFactory.buildStandardProperty( attributeBinding, false );
propertyIndexes.put( attributeBinding.getAttribute().getName(), i );
i++;
}
entityMode = component.seekEntityBinding().getHierarchyDetails().getEntityMode();
// todo : move this to SF per HHH-3517; also see HHH-1907 and ComponentMetamodel
final ComponentTuplizerFactory componentTuplizerFactory = new ComponentTuplizerFactory();
// TODO: provide support for custom tuplizer
final String tuplizerClassName = null;
if ( tuplizerClassName == null ) {
componentTuplizer = componentTuplizerFactory.constructDefaultTuplizer( entityMode, component );
}
else {
componentTuplizer = componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
}
}
public boolean isKey() {
return isKey;
}
@ -103,11 +128,11 @@ public class ComponentMetamodel implements Serializable {
}
public int getPropertyIndex(String propertyName) {
Integer index = ( Integer ) propertyIndexes.get( propertyName );
Integer index = propertyIndexes.get( propertyName );
if ( index == null ) {
throw new HibernateException( "component does not contain such a property [" + propertyName + "]" );
}
return index.intValue();
return index;
}
public StandardProperty getProperty(String propertyName) {

View File

@ -32,6 +32,7 @@ import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.Component;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
/**
* A registry allowing users to define the default {@link ComponentTuplizer} class to use per {@link EntityMode}.
@ -40,6 +41,8 @@ import org.hibernate.mapping.Component;
*/
public class ComponentTuplizerFactory implements Serializable {
private static final Class[] COMPONENT_TUP_CTOR_SIG = new Class[] { Component.class };
private static final Class[] COMPONENT_TUP_CTOR_SIG_NEW = new Class[] { CompositeAttributeBinding.class };
private Map<EntityMode,Class<? extends ComponentTuplizer>> defaultImplClassByMode = buildBaseMapping();
@ -53,9 +56,11 @@ public class ComponentTuplizerFactory implements Serializable {
public void registerDefaultTuplizerClass(EntityMode entityMode, Class<? extends ComponentTuplizer> tuplizerClass) {
assert isComponentTuplizerImplementor( tuplizerClass )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] does not implement " + ComponentTuplizer.class.getName();
assert hasProperConstructor( tuplizerClass )
// TODO: for now we need constructors for both PersistentClass and EntityBinding
assert hasProperConstructor( tuplizerClass, COMPONENT_TUP_CTOR_SIG )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable";
assert hasProperConstructor( tuplizerClass, COMPONENT_TUP_CTOR_SIG_NEW )
: "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable";
defaultImplClassByMode.put( entityMode, tuplizerClass );
}
@ -81,6 +86,28 @@ public class ComponentTuplizerFactory implements Serializable {
}
}
/**
* 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.
*/
@SuppressWarnings({ "unchecked" })
public ComponentTuplizer constructTuplizer(String tuplizerClassName, CompositeAttributeBinding metadata) {
try {
Class<? extends ComponentTuplizer> 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.
*
@ -92,7 +119,28 @@ public class ComponentTuplizerFactory implements Serializable {
* @throws HibernateException if the {@link java.lang.reflect.Constructor#newInstance} call fails.
*/
public ComponentTuplizer constructTuplizer(Class<? extends ComponentTuplizer> tuplizerClass, Component metadata) {
Constructor<? extends ComponentTuplizer> constructor = getProperConstructor( tuplizerClass );
Constructor<? extends ComponentTuplizer> constructor = getProperConstructor( tuplizerClass, COMPONENT_TUP_CTOR_SIG );
assert constructor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]";
try {
return constructor.newInstance( metadata );
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to instantiate default tuplizer [" + tuplizerClass.getName() + "]", t );
}
}
/**
* 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<? extends ComponentTuplizer> tuplizerClass, CompositeAttributeBinding metadata) {
Constructor<? extends ComponentTuplizer> constructor = getProperConstructor( tuplizerClass, COMPONENT_TUP_CTOR_SIG_NEW );
assert constructor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]";
try {
return constructor.newInstance( metadata );
@ -122,19 +170,41 @@ public class ComponentTuplizerFactory implements Serializable {
return constructTuplizer( tuplizerClass, metadata );
}
/**
* 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, CompositeAttributeBinding metadata) {
Class<? extends ComponentTuplizer> tuplizerClass = 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 );
}
@SuppressWarnings({ "unchecked" })
private boolean hasProperConstructor(Class tuplizerClass) {
return getProperConstructor( tuplizerClass ) != null;
private boolean hasProperConstructor(Class tuplizerClass, Class[] clazzConstructorSignature) {
return getProperConstructor( tuplizerClass, clazzConstructorSignature ) != null;
}
private Constructor<? extends ComponentTuplizer> getProperConstructor(Class<? extends ComponentTuplizer> clazz) {
private Constructor<? extends ComponentTuplizer> getProperConstructor(
Class<? extends ComponentTuplizer> clazz,
Class[] clazzConstructorSignature) {
Constructor<? extends ComponentTuplizer> constructor = null;
try {
constructor = clazz.getDeclaredConstructor( COMPONENT_TUP_CTOR_SIG );
constructor = clazz.getDeclaredConstructor( clazzConstructorSignature );
if ( ! ReflectHelper.isPublic( constructor ) ) {
try {
// found a constructor, but it was not publicly accessible so try to request accessibility

View File

@ -27,12 +27,15 @@ import java.util.Map;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.tuple.DynamicMapInstantiator;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PropertyFactory;
/**
* A {@link ComponentTuplizer} specific to the dynamic-map entity mode.
@ -66,4 +69,8 @@ public class DynamicMapComponentTuplizer extends AbstractComponentTuplizer {
return buildPropertyAccessor(prop).getSetter( null, prop.getName() );
}
@Override
protected Instantiator buildInstantiator(CompositeAttributeBinding component) {
return new DynamicMapInstantiator();
}
}

View File

@ -35,6 +35,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
@ -42,6 +44,7 @@ import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PojoInstantiator;
import org.hibernate.tuple.PropertyFactory;
/**
* A {@link ComponentTuplizer} specific to the pojo entity mode.
@ -92,6 +95,44 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
}
}
public PojoComponentTuplizer(CompositeAttributeBinding component) {
super( component );
this.componentClass = component.getClassReference();
String[] getterNames = new String[propertySpan];
String[] setterNames = new String[propertySpan];
Class[] propTypes = new Class[propertySpan];
for ( int i = 0; i < propertySpan; i++ ) {
getterNames[i] = getters[i].getMethodName();
setterNames[i] = setters[i].getMethodName();
propTypes[i] = getters[i].getReturnType();
}
final String parentPropertyName =
component.getParentReference() == null ? null : component.getParentReference().getName();
if ( parentPropertyName == null ) {
parentSetter = null;
parentGetter = null;
}
else {
PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( null );
parentSetter = pa.getSetter( componentClass, parentPropertyName );
parentGetter = pa.getGetter( componentClass, parentPropertyName );
}
if ( hasCustomAccessors || !Environment.useReflectionOptimizer() ) {
optimizer = null;
}
else {
// TODO: here is why we need to make bytecode provider global :(
// TODO : again, fix this after HHH-1907 is complete
optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(
componentClass, getterNames, setterNames, propTypes
);
}
}
public Class getMappedClass() {
return componentClass;
}
@ -159,6 +200,18 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
return prop.getSetter( component.getComponentClass() );
}
protected Instantiator buildInstantiator(CompositeAttributeBinding component) {
if ( component.getAttribute().isSynthetic() && ReflectHelper.isAbstractClass( component.getClassReference() ) ) {
return new ProxiedInstantiator( component );
}
if ( optimizer == null ) {
return new PojoInstantiator( component, null );
}
else {
return new PojoInstantiator( component, optimizer.getInstantiationOptimizer() );
}
}
private static class ProxiedInstantiator implements Instantiator {
private final Class proxiedClass;
private final BasicProxyFactory factory;
@ -177,6 +230,20 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer {
}
}
public ProxiedInstantiator(CompositeAttributeBinding component) {
proxiedClass = component.getClassReference();
if ( proxiedClass.isInterface() ) {
factory = Environment.getBytecodeProvider()
.getProxyFactoryFactory()
.buildBasicProxyFactory( null, new Class[] { proxiedClass } );
}
else {
factory = Environment.getBytecodeProvider()
.getProxyFactoryFactory()
.buildBasicProxyFactory( proxiedClass, null );
}
}
public Object instantiate(Serializable id) {
throw new AssertionFailure( "ProxiedInstantiator can only be used to instantiate component" );
}

View File

@ -43,6 +43,7 @@ import org.hibernate.proxy.ProxyFactory;
import org.hibernate.proxy.map.MapProxyFactory;
import org.hibernate.tuple.DynamicMapInstantiator;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PropertyFactory;
/**
* An {@link EntityTuplizer} specific to the dynamic-map entity mode.
@ -128,21 +129,12 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer {
return pf;
}
private PropertyAccessor buildPropertyAccessor(AttributeBinding mappedProperty) {
if ( mappedProperty.isBackRef() ) {
return PropertyAccessorFactory.getPropertyAccessor( null, mappedProperty.getPropertyAccessorName() );
}
else {
return PropertyAccessorFactory.getDynamicMapPropertyAccessor();
}
}
/**
* {@inheritDoc}
*/
@Override
protected Getter buildPropertyGetter(AttributeBinding mappedProperty) {
return buildPropertyAccessor( mappedProperty ).getGetter( null, mappedProperty.getAttribute().getName() );
return PropertyFactory.getGetter( mappedProperty );
}
/**
@ -150,7 +142,7 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer {
*/
@Override
protected Setter buildPropertySetter(AttributeBinding mappedProperty) {
return buildPropertyAccessor( mappedProperty ).getSetter( null, mappedProperty.getAttribute().getName() );
return PropertyFactory.getSetter( mappedProperty );
}
/**

View File

@ -36,7 +36,6 @@ import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
@ -52,13 +51,12 @@ import org.hibernate.mapping.Subclass;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PojoInstantiator;
import org.hibernate.tuple.PropertyFactory;
import org.hibernate.type.CompositeType;
/**
@ -295,11 +293,11 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
}
for ( AttributeBinding property : entityBinding.attributeBindings() ) {
Method method = getGetter( property ).getMethod();
Method method = PropertyFactory.getGetter( property ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.gettersOfLazyClassesCannotBeFinal(entityBinding.getEntity().getName(), property.getAttribute().getName());
}
method = getSetter( property ).getMethod();
method = PropertyFactory.getSetter( property ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.settersOfLazyClassesCannotBeFinal(entityBinding.getEntity().getName(), property.getAttribute().getName());
}
@ -448,7 +446,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
*/
@Override
protected Getter buildPropertyGetter(AttributeBinding mappedProperty) {
return getGetter( mappedProperty );
return PropertyFactory.getGetter( mappedProperty );
}
/**
@ -456,26 +454,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
*/
@Override
protected Setter buildPropertySetter(AttributeBinding mappedProperty) {
return getSetter( mappedProperty );
}
private Getter getGetter(AttributeBinding mappedProperty) throws PropertyNotFoundException, MappingException {
return getPropertyAccessor( mappedProperty ).getGetter(
mappedProperty.getContainer().getClassReference(),
mappedProperty.getAttribute().getName()
);
}
private Setter getSetter(AttributeBinding mappedProperty) throws PropertyNotFoundException, MappingException {
return getPropertyAccessor( mappedProperty ).getSetter(
mappedProperty.getContainer().getClassReference(),
mappedProperty.getAttribute().getName()
);
}
private PropertyAccessor getPropertyAccessor(AttributeBinding mappedProperty) throws MappingException {
// TODO: Fix this then backrefs are working in new metamodel
return PropertyAccessorFactory.getPropertyAccessor( mappedProperty, getEntityMode() );
return PropertyFactory.getSetter( mappedProperty );
}
/**

View File

@ -301,6 +301,15 @@ public class EmbeddableBindingTest extends BaseAnnotationBindingTestCase {
private String test;
@Parent
private MainEntity parent;
// require getter/setter for parent because of HHH-1614
public MainEntity getParent() {
return parent;
}
public void setParent(MainEntity parent) {
this.parent = parent;
}
}
@Entity
@ -331,13 +340,21 @@ public class EmbeddableBindingTest extends BaseAnnotationBindingTestCase {
public interface Car {
int getHorsePower();
void setHorsePower(int horsePower);
}
@Embeddable
public class CarImpl implements Car {
private int horsePower;
@Override
public int getHorsePower() {
return 0;
return horsePower;
}
@Override
public void setHorsePower(int horsePower) {
this.horsePower = horsePower;
}
}

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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
*/
package org.hibernate.test.bidir.onetomany.nonindexed;
import org.junit.Test;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Gail Badner
*/
public class AbstractBidirectionalOneToManyTest extends BaseCoreFunctionalTestCase {
@Override
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( USE_NEW_METADATA_MAPPINGS, "true");
}
@Test
public void testDoNothing() {
}
}

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.bidir.onetomany.nonindexed.inverse;
package org.hibernate.test.bidir.onetomany.nonindexed;
import org.junit.Test;
@ -31,20 +31,10 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Gail Badner
*/
public class BidirectionalOneToManyInverseTest extends BaseCoreFunctionalTestCase {
public class BidirectionalOneToManyInverseTest extends AbstractBidirectionalOneToManyTest {
@Override
public String[] getMappings() {
return new String[] { "bidir/onetomany/nonindexed/inverse/ParentChild.hbm.xml" };
}
@Override
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( USE_NEW_METADATA_MAPPINGS, "true");
}
@Test
public void testDoNothing() {
return new String[] { "bidir/onetomany/nonindexed/ParentChildInverseOneToMany.hbm.xml" };
}
}

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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
*/
package org.hibernate.test.bidir.onetomany.nonindexed;
/**
* @author Gail Badner
*/
public class BidirectionalOneToManyNonInverseTest extends AbstractBidirectionalOneToManyTest {
@Override
public String[] getMappings() {
return new String[] { "bidir/onetomany/nonindexed/ParentChildNonInverseOneToMany.hbm.xml" };
}
}

View File

@ -1,5 +1,5 @@
//$Id: Child.java 5686 2005-02-12 07:27:32Z steveebersole $
package org.hibernate.test.bidir.onetomany.nonindexed.inverse;
package org.hibernate.test.bidir.onetomany.nonindexed;

View File

@ -1,5 +1,5 @@
//$Id: Parent.java 5686 2005-02-12 07:27:32Z steveebersole $
package org.hibernate.test.bidir.onetomany.nonindexed.inverse;
package org.hibernate.test.bidir.onetomany.nonindexed;
import java.util.HashSet;
import java.util.Set;

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<hibernate-mapping package="org.hibernate.test.bidir.onetomany.nonindexed.inverse"
<hibernate-mapping package="org.hibernate.test.bidir.onetomany.nonindexed"
xmlns="http://www.hibernate.org/xsd/hibernate-mapping">
<class name="Child">

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<hibernate-mapping package="org.hibernate.test.bidir.onetomany.nonindexed"
xmlns="http://www.hibernate.org/xsd/hibernate-mapping">
<class name="Child">
<id name="name"/>
<property name="age" not-null="true"/>
<many-to-one name="parent" column="parent_id" insert="false" update="false"/>
</class>
<class name="Parent">
<id name="name"/>
<set name="children" cascade="persist,merge" inverse="false">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
</hibernate-mapping>