diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java index 04c6a68ad2..5e64ee253a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java @@ -52,7 +52,6 @@ import org.hibernate.metamodel.spi.binding.BasicPluralAttributeElementBinding; import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityDiscriminator; -import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.spi.binding.IdGenerator; import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding; @@ -134,6 +133,7 @@ import org.hibernate.type.Type; * * @author Steve Ebersole * @author Hardy Ferentschik + * @author Gail Badner */ public class Binder { private final MetadataImplementor metadata; @@ -898,6 +898,12 @@ public class Binder { attributeSource.metaAttributes(), attributeBindingContainer.getMetaAttributeContext() ); + + // TODO: referenced attribute binding may not be defined yet; if it doesn't, need to chase it + // before resolving types. + SingularAttributeBinding referencedAttributeBinding = locatePluralAttributeKeyReferencedBinding( + attributeSource, attributeBindingContainer + ); if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) { final PluralAttribute attribute = existingAttribute != null ? existingAttribute @@ -905,6 +911,7 @@ public class Binder { pluralAttributeBinding = attributeBindingContainer.makeBagAttributeBinding( attribute, convert( attributeSource.getElementSource().getNature() ), + referencedAttributeBinding, propertyAccessorName, attributeSource.isIncludedInOptimisticLocking(), false, @@ -919,6 +926,7 @@ public class Binder { pluralAttributeBinding = attributeBindingContainer.makeSetAttributeBinding( attribute, convert( attributeSource.getElementSource().getNature() ), + referencedAttributeBinding, propertyAccessorName, attributeSource.isIncludedInOptimisticLocking(), false, @@ -941,9 +949,41 @@ public class Binder { bindCollectionIndex( attributeSource, pluralAttributeBinding ); bindCollectionTablePrimaryKey( attributeSource, pluralAttributeBinding ); + typeHelper.bindPluralAttributeTypeInformation( attributeSource, pluralAttributeBinding ); + metadata.addCollection( pluralAttributeBinding ); } + private SingularAttributeBinding locatePluralAttributeKeyReferencedBinding( + PluralAttributeSource attributeSource, + AttributeBindingContainer attributeBindingContainer) { + final EntityBinding entityBinding = attributeBindingContainer.seekEntityBinding(); + final String referencedAttributeName = attributeSource.getKeySource().getReferencedEntityAttributeName(); + AttributeBinding referencedAttributeBinding = + attributeSource.getKeySource().getReferencedEntityAttributeName() == null ? + entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() : + entityBinding.locateAttributeBinding( referencedAttributeName ); + if ( referencedAttributeBinding == null ) { + throw new MappingException( + String.format( + "Plural atttribute key references an attribute binding that does not exist: %s", + referencedAttributeBinding + ), + currentBindingContext.getOrigin() + ); + } + if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { + throw new MappingException( + String.format( + "Plural atttribute key references a plural attribute; it must be plural: %s", + referencedAttributeName + ), + currentBindingContext.getOrigin() + ); + } + return ( SingularAttributeBinding ) referencedAttributeBinding; + } + private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) { binding.setFetchTiming( source.getFetchTiming() ); binding.setFetchStyle( source.getFetchStyle() ); @@ -1063,36 +1103,6 @@ public class Binder { else { bindCollectionKeyTargetingPropertyRef( attributeSource.getKeySource(), pluralAttributeBinding ); } - - final EntityBinding entityBinding = pluralAttributeBinding.getContainer().seekEntityBinding(); - AttributeBinding referencedAttributeBinding = - attributeSource.getKeySource().getReferencedEntityAttributeName() == null ? - entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() : - entityBinding.locateAttributeBinding( attributeSource.getKeySource().getReferencedEntityAttributeName() ); - - if ( referencedAttributeBinding == null ) { - throw new MappingException( - String.format( - "Plural atttribute key references an attribute binding that does not exist: %s", - attributeSource.getKeySource().getReferencedEntityAttributeName() - ), - currentBindingContext.getOrigin() - ); - } - if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { - throw new MappingException( - String.format( - "Plural attribute key references an attribute that is not singular: %s", - attributeSource.getKeySource().getReferencedEntityAttributeName() - ), - currentBindingContext.getOrigin() - ); - } - - typeHelper.bindPluralAttributeKeyTypeInformation( - pluralAttributeBinding.getPluralAttributeKeyBinding(), - ( SingularAttributeBinding ) referencedAttributeBinding - ); } private void bindCollectionKeyTargetingPrimaryKey( @@ -1263,10 +1273,6 @@ public class Binder { basicElementSource, basicCollectionElement ); - typeHelper.bindPluralAttributeTypeInformation( - attributeSource, - pluralAttributeBinding - ); return; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java index 03e9ceff76..c7436ca70f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java @@ -91,6 +91,7 @@ import org.hibernate.type.TypeFactory; * * * @author Steve Ebersole + * @author Gail Badner */ public class HibernateTypeHelper { private static final Logger log = Logger.getLogger( HibernateTypeHelper.class ); @@ -159,16 +160,18 @@ public class HibernateTypeHelper { } } - //todo : we need to support type descriptors at multiple levels - bindHibernateTypeInformation( attributeSource.getTypeInformation(), attributeBinding.getHibernateTypeDescriptor() ); + bindHibernateTypeInformation( + attributeSource.getTypeInformation(), + attributeBinding.getHibernateTypeDescriptor() + ); processPluralAttributeTypeInformation( attributeBinding ); } - public void bindPluralAttributeKeyTypeInformation( - PluralAttributeKeyBinding keyBinding, - SingularAttributeBinding referencedAttributeBinding) { + private void processPluralAttributeKeyTypeInformation(PluralAttributeKeyBinding keyBinding) { final HibernateTypeDescriptor pluralAttributeKeyTypeDescriptor = keyBinding.getHibernateTypeDescriptor(); - final HibernateTypeDescriptor referencedTypeDescriptor = referencedAttributeBinding.getHibernateTypeDescriptor(); + final HibernateTypeDescriptor referencedTypeDescriptor = + keyBinding.getReferencedAttributeBinding().getHibernateTypeDescriptor(); + pluralAttributeKeyTypeDescriptor.setExplicitTypeName( referencedTypeDescriptor.getExplicitTypeName() ); pluralAttributeKeyTypeDescriptor.setJavaTypeName( referencedTypeDescriptor.getJavaTypeName() ); @@ -176,12 +179,10 @@ public class HibernateTypeHelper { pluralAttributeKeyTypeDescriptor.setToOne( referencedTypeDescriptor.isToOne() ); pluralAttributeKeyTypeDescriptor.getTypeParameters().putAll( referencedTypeDescriptor.getTypeParameters() ); - processPluralAttributeKeyInformation( keyBinding, referencedAttributeBinding ); + processPluralAttributeKeyInformation( keyBinding ); } - private void processPluralAttributeKeyInformation( - PluralAttributeKeyBinding keyBinding, - SingularAttributeBinding referencedAttributeBinding) { + private void processPluralAttributeKeyInformation(PluralAttributeKeyBinding keyBinding) { if ( keyBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() != null ) { return; } @@ -190,7 +191,9 @@ public class HibernateTypeHelper { // 2) we know the java type of the attribute Type resolvedType = determineHibernateTypeFromDescriptor( keyBinding.getHibernateTypeDescriptor() ); if ( resolvedType == null ) { - resolvedType = determineHibernateTypeFromAttributeJavaType( referencedAttributeBinding.getAttribute() ); + resolvedType = determineHibernateTypeFromAttributeJavaType( + keyBinding.getReferencedAttributeBinding().getAttribute() + ); } if ( resolvedType != null ) { @@ -444,6 +447,12 @@ public class HibernateTypeHelper { } private void processPluralAttributeTypeInformation(PluralAttributeBinding attributeBinding) { + processCollectionTypeInformation( attributeBinding ); + processPluralAttributeElementTypeInformation( attributeBinding.getPluralAttributeElementBinding() ); + processPluralAttributeKeyTypeInformation( attributeBinding.getPluralAttributeKeyBinding() ); + } + + private void processCollectionTypeInformation(PluralAttributeBinding attributeBinding) { if ( attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() != null ) { return; } @@ -469,14 +478,8 @@ public class HibernateTypeHelper { resolvedType = determineHibernateTypeFromCollectionType( attributeBinding ); } if ( resolvedType != null ) { -// todo : what exactly is getting pushed down here? and to what/where? -// pushHibernateTypeInformationDownIfNeeded( -// attributeBinding.getHibernateTypeDescriptor(), -// null, -// resolvedType -// ); + attributeBinding.getHibernateTypeDescriptor().setResolvedTypeMapping( resolvedType ); } - bindCollectionElementTypeInformation( attributeBinding.getPluralAttributeElementBinding() ); } private Type determineHibernateTypeFromCollectionType(PluralAttributeBinding attributeBinding) { @@ -505,10 +508,12 @@ public class HibernateTypeHelper { } } - private void bindCollectionElementTypeInformation(PluralAttributeElementBinding pluralAttributeElementBinding) { + private void processPluralAttributeElementTypeInformation( + PluralAttributeElementBinding pluralAttributeElementBinding + ) { switch ( pluralAttributeElementBinding.getPluralAttributeElementNature() ) { case BASIC: { - bindBasicCollectionElementTypeInformation( + processBasicCollectionElementTypeInformation( BasicPluralAttributeElementBinding.class.cast( pluralAttributeElementBinding ) @@ -528,7 +533,7 @@ public class HibernateTypeHelper { } } - private void bindBasicCollectionElementTypeInformation(BasicPluralAttributeElementBinding basicCollectionElement) { + private void processBasicCollectionElementTypeInformation(BasicPluralAttributeElementBinding basicCollectionElement) { Type resolvedHibernateType = determineHibernateTypeFromDescriptor( basicCollectionElement.getHibernateTypeDescriptor() ); if ( resolvedHibernateType != null ) { pushHibernateTypeInformationDown( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java index 620ccf0dcb..df026e7d9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java @@ -79,6 +79,7 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi AttributeBindingContainer container, PluralAttribute attribute, PluralAttributeElementNature pluralAttributeElementNature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean isLazy, @@ -91,7 +92,7 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi isLazy, metaAttributeContext ); - this.pluralAttributeKeyBinding = new PluralAttributeKeyBinding( this ); + this.pluralAttributeKeyBinding = new PluralAttributeKeyBinding( this, referencedAttributeBinding ); this.pluralAttributeElementBinding = interpretNature( pluralAttributeElementNature ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java index d87711451e..7a8951180b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java @@ -131,6 +131,7 @@ public interface AttributeBindingContainer { public BagBinding makeBagAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -147,6 +148,7 @@ public interface AttributeBindingContainer { public SetBinding makeSetAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BagBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BagBinding.java index 04fc168fdc..8d91f1ed0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BagBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BagBinding.java @@ -36,6 +36,7 @@ public class BagBinding extends AbstractPluralAttributeBinding { AttributeBindingContainer container, PluralAttribute attribute, PluralAttributeElementNature pluralAttributeElementNature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean isLazy, @@ -44,6 +45,7 @@ public class BagBinding extends AbstractPluralAttributeBinding { container, attribute, pluralAttributeElementNature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, isLazy, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java index 60535bcd11..0d7c872571 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java @@ -205,6 +205,7 @@ public class CompositeAttributeBinding public BagBinding makeBagAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -214,6 +215,7 @@ public class CompositeAttributeBinding this, attribute, nature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, lazy, @@ -227,6 +229,7 @@ public class CompositeAttributeBinding public SetBinding makeSetAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -237,6 +240,7 @@ public class CompositeAttributeBinding this, attribute, nature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, lazy, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java index d58dd8d20a..1d6e99b512 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java @@ -559,6 +559,7 @@ public class EntityBinding implements AttributeBindingContainer { public BagBinding makeBagAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -568,6 +569,7 @@ public class EntityBinding implements AttributeBindingContainer { this, attribute, nature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, lazy, @@ -581,6 +583,7 @@ public class EntityBinding implements AttributeBindingContainer { public SetBinding makeSetAttributeBinding( PluralAttribute attribute, PluralAttributeElementNature nature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -591,6 +594,7 @@ public class EntityBinding implements AttributeBindingContainer { this, attribute, nature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, lazy, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java index bec1afcd4e..aeb1783fd2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java @@ -41,14 +41,17 @@ public class PluralAttributeKeyBinding { // this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); - // SingularAttributeBinding referencedAttributeBinding; + private final SingularAttributeBinding referencedAttributeBinding; // todo : this would be nice to have but we do not always know it, especially in HBM case. // private BasicAttributeBinding otherSide; - public PluralAttributeKeyBinding(AbstractPluralAttributeBinding pluralAttributeBinding) { + public PluralAttributeKeyBinding( + AbstractPluralAttributeBinding pluralAttributeBinding, + SingularAttributeBinding referencedAttributeBinding) { this.pluralAttributeBinding = pluralAttributeBinding; + this.referencedAttributeBinding = referencedAttributeBinding; } /** @@ -60,6 +63,9 @@ public class PluralAttributeKeyBinding { return pluralAttributeBinding; } + public SingularAttributeBinding getReferencedAttributeBinding() { + return referencedAttributeBinding; + } /** * The foreign key that defines the scope of this relationship. * diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/SetBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/SetBinding.java index c83357b388..804a5d22ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/SetBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/SetBinding.java @@ -38,6 +38,7 @@ public class SetBinding extends AbstractPluralAttributeBinding { AttributeBindingContainer container, PluralAttribute attribute, PluralAttributeElementNature pluralAttributeElementNature, + SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, boolean isLazy, @@ -47,6 +48,7 @@ public class SetBinding extends AbstractPluralAttributeBinding { container, attribute, pluralAttributeElementNature, + referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, isLazy, diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java index bf6156f0f0..77a3a7771d 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java @@ -23,7 +23,10 @@ */ package org.hibernate.metamodel.spi.binding; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.Set; import org.junit.After; import org.junit.Before; @@ -38,6 +41,8 @@ import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.internal.StandardServiceRegistryImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.type.BagType; +import org.hibernate.type.SetType; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -89,6 +94,13 @@ public class BasicCollectionBindingTests extends BaseUnitTestCase { assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theBag`" ), bagBinding.getCollectionTable().getLogicalName() ); PluralAttributeKeyBinding bagKeyBinding = bagBinding.getPluralAttributeKeyBinding(); assertSame( bagBinding, bagKeyBinding.getPluralAttributeBinding() ); + HibernateTypeDescriptor bagHibernateTypeDescriptor = bagBinding.getHibernateTypeDescriptor(); + assertNull( bagHibernateTypeDescriptor.getExplicitTypeName() ); + assertEquals( Collection.class.getName(), bagHibernateTypeDescriptor.getJavaTypeName() ); + assertTrue( bagHibernateTypeDescriptor.getTypeParameters().isEmpty() ); + assertTrue( bagHibernateTypeDescriptor.getResolvedTypeMapping() instanceof BagType ); + assertFalse( bagHibernateTypeDescriptor.getResolvedTypeMapping().isComponentType() ); + assertEquals( "theBag", ( (BagType) bagHibernateTypeDescriptor.getResolvedTypeMapping() ).getRole() ); ForeignKey fkBag = bagKeyBinding.getForeignKey(); assertNotNull( fkBag ); @@ -130,6 +142,13 @@ public class BasicCollectionBindingTests extends BaseUnitTestCase { assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theSet`" ), setBinding.getCollectionTable().getLogicalName() ); PluralAttributeKeyBinding setKeyBinding = setBinding.getPluralAttributeKeyBinding(); assertSame( setBinding, setKeyBinding.getPluralAttributeBinding() ); + HibernateTypeDescriptor setHibernateTypeDescriptor = setBinding.getHibernateTypeDescriptor(); + assertNull( setHibernateTypeDescriptor.getExplicitTypeName() ); + assertEquals( Set.class.getName(), setHibernateTypeDescriptor.getJavaTypeName() ); + assertTrue( setHibernateTypeDescriptor.getTypeParameters().isEmpty() ); + assertTrue( setHibernateTypeDescriptor.getResolvedTypeMapping() instanceof SetType ); + assertFalse( setHibernateTypeDescriptor.getResolvedTypeMapping().isComponentType() ); + assertEquals( "theSet", ( (SetType) setHibernateTypeDescriptor.getResolvedTypeMapping() ).getRole() ); ForeignKey fkSet = setKeyBinding.getForeignKey(); assertNotNull( fkSet );