From bd7605da01c9c5c5c2664eb007385c2bdbd82ef9 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 24 Apr 2014 15:27:53 -0500 Subject: [PATCH] HHH-9055 - Binding support for IdClass and MapsId needs a complete review --- .../cfg/beanvalidation/TypeSafeActivator.java | 17 +- .../internal/MetadataBuildingProcess.java | 110 +- .../metamodel/internal/MetadataImpl.java | 20 +- .../binder/AttributeBindingListener.java | 34 + .../binder/AttributeBindingProducer.java | 30 + .../metamodel/internal/binder/Binder.java | 2372 +++++++++++++---- .../internal/binder/BinderEventBus.java | 163 ++ ...BinderLocalBindingContextSelectorImpl.java | 10 + .../internal/binder/BinderProcessHelper.java | 111 +- .../internal/binder/BinderRootContext.java | 4 + .../binder/BinderRootContextImpl.java | 15 +- .../binder/BinderStepEntityStrategy.java | 2 + .../internal/binder/ForeignKeyHelper.java | 49 +- .../internal/binder/HibernateTypeHelper.java | 53 +- .../binder/IdentifierBindingListener.java | 40 + .../internal/binder/SourceIndex.java | 573 ++-- .../annotations/AbstractIdentifierSource.java | 37 - .../AbstractToOneAttributeSourceImpl.java | 42 - ...gregatedCompositeIdentifierSourceImpl.java | 17 +- .../EntityHierarchySourceImpl.java | 3 +- .../annotations/EntitySourceImpl.java | 2 +- .../annotations/HibernateTypeSourceImpl.java | 65 +- ...gregatedCompositeIdentifierSourceImpl.java | 205 +- ...ralAttributeSequentialIndexSourceImpl.java | 29 +- .../PluralAttributeSourceImpl.java | 56 +- .../annotations/RootEntitySourceImpl.java | 12 + .../SimpleIdentifierSourceImpl.java | 5 - .../internal/annotations/SourceHelper.java | 35 + .../annotations/ToOneAttributeSourceImpl.java | 75 +- .../ToOneMappedByAttributeSourceImpl.java | 7 +- .../entity/EmbeddableTypeMetadata.java | 13 +- .../entity/IdentifiableTypeMetadata.java | 26 + .../entity/ManagedTypeMetadata.java | 36 +- .../global/SqlResultSetProcessor.java | 22 +- .../annotations/util/AssociationHelper.java | 4 +- .../AbstractPluralAttributeSourceImpl.java | 16 +- .../hbm/AbstractToOneAttributeSourceImpl.java | 35 +- .../hbm/EntityHierarchySourceImpl.java | 194 +- .../metamodel/source/internal/hbm/Helper.java | 16 - .../internal/hbm/HibernateTypeSourceImpl.java | 83 + .../source/internal/hbm/IdBagSourceImpl.java | 30 +- .../internal/hbm/KeyAttributeSourceImpl.java | 37 +- .../internal/hbm/KeyManyToOneSourceImpl.java | 20 + .../hbm/ManyToOneAttributeSourceImpl.java | 21 + .../internal/hbm/MapKeySourceBasicImpl.java | 67 +- .../hbm/OneToOneAttributeSourceImpl.java | 24 +- ...PluralAttributeElementSourceBasicImpl.java | 49 +- ...ralAttributeSequentialIndexSourceImpl.java | 165 +- .../hbm/PropertyAttributeSourceImpl.java | 37 +- ...SingularIdentifierAttributeSourceImpl.java | 38 +- .../hbm/TimestampAttributeSourceImpl.java | 30 +- .../hbm/VersionAttributeSourceImpl.java | 29 +- .../AggregatedCompositeIdentifierSource.java | 18 +- .../source/spi/CompositeIdentifierSource.java | 4 + .../source/spi/IdentifierSource.java | 15 - .../spi/JavaTypeDescriptorResolvable.java | 33 + .../metamodel/source/spi/MapsIdSource.java | 46 + ...onAggregatedCompositeIdentifierSource.java | 9 + .../source/spi/ToOneAttributeSource.java | 20 - .../ToOneAttributeSourceNatureResolver.java | 11 +- .../metamodel/spi/AbstractAttributeKey.java | 13 + ...ractPersistentAttributeMemberResolver.java | 4 +- .../spi/BaseDelegatingBindingContext.java | 52 + .../metamodel/spi/BindingContext.java | 26 + .../AbstractAttributeBindingContainer.java | 2 +- .../binding/AbstractEmbeddableBinding.java | 5 +- .../spi/binding/BasicAttributeBinding.java | 2 +- .../CompositePluralAttributeIndexBinding.java | 8 +- .../spi/binding/EmbeddableBinding.java | 3 + .../binding/EmbeddableBindingImplementor.java | 32 + .../spi/binding/EmbeddedAttributeBinding.java | 124 +- .../metamodel/spi/binding/EntityBinding.java | 56 +- .../spi/binding/EntityIdentifier.java | 755 ++++-- .../spi/binding/HibernateTypeDescriptor.java | 29 + ...PluralAttributeElementBindingEmbedded.java | 8 +- .../RelationalValueBindingContainer.java | 6 +- .../domain/AbstractAttributeContainer.java | 4 +- .../entity/AbstractEntityPersister.java | 43 +- .../hibernate/tuple/IdentifierProperty.java | 5 +- .../org/hibernate/tuple/PojoInstantiator.java | 11 +- .../org/hibernate/tuple/PropertyFactory.java | 34 +- .../component/PojoComponentTuplizer.java | 75 +- .../tuple/entity/AbstractEntityTuplizer.java | 25 +- .../tuple/entity/PojoEntityTuplizer.java | 10 +- .../annotations/entity/EmbeddedIdTest.java | 3 +- .../entity/IdentifierGeneratorTest.java | 4 +- .../entity/InheritanceBindingTest.java | 11 +- .../binding/AbstractBasicBindingTests.java | 6 +- .../binding/AbstractUnsavedValueTests.java | 8 +- .../spi/binding/SimpleValueBindingTests.java | 4 +- .../spi/binding/UnsavedValueHbmTests.java | 4 +- .../AbstractBasicCollectionBindingTests.java | 4 +- .../spi/binding/cid/BasicEmbeddedIdTest.java | 10 +- .../spi/binding/cid/BasicIdClassTest.java | 39 +- ...ctUnidirectionalOneToManyBindingTests.java | 8 +- .../test/annotations/fkcircularity/A_PK.java | 2 + .../test/annotations/fkcircularity/D_PK.java | 1 + .../fkcircularity/FkCircularityTest.java | 4 +- .../test/annotations/id/IdClassTest.java | 6 +- .../annotations/id/sequences/IdClassTest.java | 1 + .../annotations/manytoone/ManyToOneTest.java | 5 +- .../IntermediateMappedSuperclassTest.java | 1 - .../hibernate/test/hql/TupleSupportTest.java | 1 - .../hibernate/test/idclass/IdClassTest.java | 2 - .../org/hibernate/test/legacy/MapTest.java | 4 + .../hibernate/test/legacy/SQLLoaderTest.java | 5 + .../plans/LoadPlanStructureAssertionTest.java | 2 - .../walking/CompositesWalkingTest.java | 3 + .../org/hibernate/test/mapping/AliasTest.java | 4 +- .../metamodel/derivedid/e1/a/MappingTest.java | 15 +- .../metamodel/builder/MetamodelBuilder.java | 64 +- ...mpleEmbeddableOverriddenConverterTest.java | 2 - .../idclass/IdClassPredicateTest.java | 2 - .../metadata/IdMetadataGenerator.java | 51 +- 114 files changed, 4910 insertions(+), 2039 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingListener.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingProducer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderEventBus.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/IdentifierBindingListener.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/HibernateTypeSourceImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/JavaTypeDescriptorResolvable.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MapsIdSource.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBindingImplementor.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java index 7917f99080..c5d2636bb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java @@ -48,6 +48,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; @@ -58,6 +59,7 @@ import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.domain.Attribute; @@ -404,9 +406,18 @@ class TypeSafeActivator { * {@code propertyPath} is {@code null} or empty, the id attribute binding is returned. */ private static AttributeBinding findPropertyByName(EntityBinding entityBinding, String propertyPath) { - final AttributeBinding idAttributeBinding = entityBinding.getHierarchyDetails() - .getEntityIdentifier() - .getAttributeBinding(); + final AttributeBinding idAttributeBinding; + + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + idAttributeBinding = null; + } + else { + final EntityIdentifier.AttributeBasedIdentifierBinding identifierBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + idAttributeBinding = identifierBinding.getAttributeBinding(); + } + final String idAttributeName = idAttributeBinding == null ? null : idAttributeBinding.getAttribute().getName(); if ( propertyPath == null || propertyPath.length() == 0 || propertyPath.equals( idAttributeName ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataBuildingProcess.java index 9e9d390445..36b66ab819 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataBuildingProcess.java @@ -54,6 +54,7 @@ import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.engine.spi.SyntheticAttributeHelper; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.internal.util.collections.CollectionHelper; @@ -90,6 +91,7 @@ import org.hibernate.metamodel.spi.TypeContributor; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.BackRefAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.FetchProfile; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; import org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding; @@ -100,7 +102,11 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding; import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.SecondaryTable; import org.hibernate.metamodel.spi.binding.TypeDefinition; +import org.hibernate.metamodel.spi.domain.Aggregate; import org.hibernate.metamodel.spi.domain.BasicType; +import org.hibernate.metamodel.spi.domain.Entity; +import org.hibernate.metamodel.spi.domain.Hierarchical; +import org.hibernate.metamodel.spi.domain.MappedSuperclass; import org.hibernate.metamodel.spi.domain.SingularAttribute; import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.metamodel.spi.relational.Database; @@ -605,21 +611,97 @@ public class MetadataBuildingProcess { return javaTypeDescriptorRepository.getType( javaTypeDescriptorRepository.buildName( qualifyClassName( name ) ) ); } + private final Map domainModelTypes = new HashMap(); + + @Override + public BasicType buildBasicDomainType(JavaTypeDescriptor typeDescriptor) { + final BasicType type = new BasicType( typeDescriptor.getName().toString(), typeDescriptor ); + final Type old = domainModelTypes.put( typeDescriptor, type ); + if ( old != null ) { + log.debugf( "Building basic domain type overrode existing entry: %s", old ); + } + return type; + } + + @Override + public MappedSuperclass buildMappedSuperclassDomainType(JavaTypeDescriptor typeDescriptor) { + return buildMappedSuperclassDomainType( typeDescriptor, null ); + } + + @Override + public MappedSuperclass buildMappedSuperclassDomainType( + JavaTypeDescriptor typeDescriptor, + Hierarchical superType) { + final MappedSuperclass type = new MappedSuperclass( typeDescriptor, superType ); + final Type old = domainModelTypes.put( typeDescriptor, type ); + if ( old != null ) { + log.debugf( "Building MappedSuperclass domain type overrode existing entry: %s", old ); + } + return type; + } + + @Override + public Aggregate buildComponentDomainType(JavaTypeDescriptor typeDescriptor) { + return buildComponentDomainType( typeDescriptor, null ); + } + + @Override + public Aggregate buildComponentDomainType( + JavaTypeDescriptor typeDescriptor + , Hierarchical superType) { + final Aggregate type = new Aggregate( typeDescriptor, superType ); + final Type old = domainModelTypes.put( typeDescriptor, type ); + if ( old != null ) { + log.debugf( "Building Aggregate domain type overrode existing entry: %s", old ); + } + return type; + } + + @Override + public Entity buildEntityDomainType(JavaTypeDescriptor typeDescriptor) { + return buildEntityDomainType( typeDescriptor, null ); + } + + @Override + public Entity buildEntityDomainType( + JavaTypeDescriptor typeDescriptor, + Hierarchical superType) { + final Entity type = new Entity( typeDescriptor, superType ); + final Type old = domainModelTypes.put( typeDescriptor, type ); + if ( old != null ) { + log.debugf( "Building Entity domain type overrode existing entry: %s", old ); + } + return type; + } + + @Override + public Type locateDomainType(JavaTypeDescriptor typeDescriptor) { + return domainModelTypes.get( typeDescriptor ); + } + + @Override + public Type locateOrBuildDomainType(JavaTypeDescriptor typeDescriptor, boolean isAggregate) { + Type type = domainModelTypes.get( typeDescriptor ); + if ( type == null ) { + type = isAggregate + ? buildComponentDomainType( typeDescriptor ) + : buildBasicDomainType( typeDescriptor ); + } + return type; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BindingContext deprecated impls @Override public Type makeDomainType(String className) { - return new BasicType( className, typeDescriptor( className ) ); + return buildBasicDomainType( typeDescriptor( className ) ); } @Override public Type makeDomainType(DotName typeName) { - return new BasicType( - typeName.toString(), - typeDescriptor( typeName.toString() ) - ); + return buildBasicDomainType( typeDescriptor( typeName.toString() ) ); } } @@ -1143,9 +1225,10 @@ public class MetadataBuildingProcess { if ( entityBinding == null ) { throw new MappingException( "Entity binding not known: " + entityName ); } - return entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() - .getHibernateTypeDescriptor() - .getResolvedTypeMapping(); + return entityBinding.getHierarchyDetails() + .getEntityIdentifier() + .getEntityIdentifierBinding() + .getHibernateType(); } @Override @@ -1154,8 +1237,15 @@ public class MetadataBuildingProcess { if ( entityBinding == null ) { throw new MappingException( "Entity binding not known: " + entityName ); } - AttributeBinding idBinding = entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - return idBinding == null ? null : idBinding.getAttribute().getName(); + + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + return null; + } + + final EntityIdentifier.AttributeBasedIdentifierBinding identifierBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + return identifierBinding.getAttributeBinding().getAttribute().getName(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java index c80a9a3bb0..833ae91e7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java @@ -38,12 +38,14 @@ import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition; import org.hibernate.metamodel.SessionFactoryBuilder; import org.hibernate.metamodel.spi.MetadataImplementor; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.FetchProfile; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; @@ -300,9 +302,10 @@ public class MetadataImpl implements MetadataImplementor, Serializable { if ( entityBinding == null ) { throw new MappingException( "Entity binding not known: " + entityName ); } - return entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() - .getHibernateTypeDescriptor() - .getResolvedTypeMapping(); + return entityBinding.getHierarchyDetails() + .getEntityIdentifier() + .getEntityIdentifierBinding() + .getHibernateType(); } @Override @@ -311,8 +314,15 @@ public class MetadataImpl implements MetadataImplementor, Serializable { if ( entityBinding == null ) { throw new MappingException( "Entity binding not known: " + entityName ); } - AttributeBinding idBinding = entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - return idBinding == null ? null : idBinding.getAttribute().getName(); + + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + return null; + } + + final EntityIdentifier.AttributeBasedIdentifierBinding identifierBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + return identifierBinding.getAttributeBinding().getAttribute().getName(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingListener.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingListener.java new file mode 100644 index 0000000000..287a3a3955 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingListener.java @@ -0,0 +1,34 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.internal.binder; + +import org.hibernate.metamodel.spi.binding.AttributeBinding; + +/** + * @author Steve Ebersole + */ +public interface AttributeBindingListener { + public void attributeBound(AttributeBinding attribute); + public void attributeResolved(AttributeBinding attribute); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingProducer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingProducer.java new file mode 100644 index 0000000000..267ab16bb5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/AttributeBindingProducer.java @@ -0,0 +1,30 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.internal.binder; + +/** + * @author Steve Ebersole + */ +public interface AttributeBindingProducer { +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/Binder.java index a52be1bcfa..7e3da6c274 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/Binder.java @@ -29,7 +29,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -60,15 +59,21 @@ import org.hibernate.id.MultipleHiLoPerTableGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.enhanced.TableGenerator; import org.hibernate.internal.FilterConfiguration; +import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.mapping.PropertyGeneration; import org.hibernate.metamodel.internal.binder.HibernateTypeHelper.ReflectedCollectionJavaTypes; import org.hibernate.metamodel.internal.resolver.AssociationRelationalBindingResolver; import org.hibernate.metamodel.internal.resolver.MappedByAssociationRelationalBindingResolverImpl; import org.hibernate.metamodel.internal.resolver.StandardAssociationRelationalBindingResolverImpl; import org.hibernate.metamodel.reflite.internal.Primitives; +import org.hibernate.metamodel.reflite.spi.ClassDescriptor; +import org.hibernate.metamodel.reflite.spi.FieldDescriptor; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptorRepository; +import org.hibernate.metamodel.reflite.spi.MemberDescriptor; +import org.hibernate.metamodel.reflite.spi.MethodDescriptor; import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.AttributeSource; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; @@ -76,6 +81,7 @@ import org.hibernate.metamodel.source.spi.ColumnSource; import org.hibernate.metamodel.source.spi.ConstraintSource; import org.hibernate.metamodel.source.spi.DerivedValueSource; import org.hibernate.metamodel.source.spi.DiscriminatorSource; +import org.hibernate.metamodel.source.spi.EmbeddableSource; import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource; import org.hibernate.metamodel.source.spi.EntityHierarchySource; import org.hibernate.metamodel.source.spi.EntitySource; @@ -86,6 +92,7 @@ import org.hibernate.metamodel.source.spi.IndexConstraintSource; import org.hibernate.metamodel.source.spi.IndexedPluralAttributeSource; import org.hibernate.metamodel.source.spi.JoinedSubclassEntitySource; import org.hibernate.metamodel.source.spi.MappedByAssociationSource; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.MetaAttributeContext; import org.hibernate.metamodel.source.spi.MultiTenancySource; import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource; @@ -110,6 +117,8 @@ import org.hibernate.metamodel.source.spi.ToOneAttributeSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; import org.hibernate.metamodel.source.spi.UniqueConstraintSource; import org.hibernate.metamodel.source.spi.VersionAttributeSource; +import org.hibernate.metamodel.spi.AbstractPersistentAttributeMemberResolver; +import org.hibernate.metamodel.spi.AttributePath; import org.hibernate.metamodel.spi.AttributeRole; import org.hibernate.metamodel.spi.BindingContext; import org.hibernate.metamodel.spi.NaturalIdMutability; @@ -117,6 +126,7 @@ import org.hibernate.metamodel.spi.PluralAttributeElementNature; import org.hibernate.metamodel.spi.PluralAttributeIndexNature; import org.hibernate.metamodel.spi.PluralAttributeNature; import org.hibernate.metamodel.spi.SingularAttributeNature; +import org.hibernate.metamodel.spi.binding.AbstractEmbeddableBinding; import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBindingContainer; @@ -126,6 +136,7 @@ import org.hibernate.metamodel.spi.binding.Caching; import org.hibernate.metamodel.spi.binding.Cascadeable; import org.hibernate.metamodel.spi.binding.CompositePluralAttributeIndexBinding; import org.hibernate.metamodel.spi.binding.EmbeddableBinding; +import org.hibernate.metamodel.spi.binding.EmbeddableBindingImplementor; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityIdentifier; @@ -160,6 +171,7 @@ import org.hibernate.metamodel.spi.domain.MappedSuperclass; import org.hibernate.metamodel.spi.domain.PluralAttribute; import org.hibernate.metamodel.spi.domain.SingularAttribute; import org.hibernate.metamodel.spi.relational.Column; +import org.hibernate.metamodel.spi.relational.DerivedValue; import org.hibernate.metamodel.spi.relational.ForeignKey; import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.PrimaryKey; @@ -179,6 +191,7 @@ import org.jboss.logging.Logger; import static org.hibernate.MultiTenancyStrategy.DISCRIMINATOR; import static org.hibernate.engine.spi.SyntheticAttributeHelper.SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME; +import static org.hibernate.metamodel.spi.binding.EntityIdentifier.NonAggregatedCompositeIdentifierBinding; /** * The common binder shared between annotations and {@code hbm.xml} processing. @@ -192,29 +205,25 @@ import static org.hibernate.engine.spi.SyntheticAttributeHelper.SYNTHETIC_COMPOS public class Binder { private static final Logger LOG = Logger.getLogger( Binder.class ); - // Entity hierarchies and source index need be available throughout the binding process - private final Map entityHierarchiesByRootEntityName = - new LinkedHashMap(); - private final SourceIndex sourceIndex = new SourceIndex(); + private final SourceIndex sourceIndex; + private final BinderEventBus eventBus; private final BinderRootContextImpl rootBindingContext; private final BinderProcessHelper processHelper; private final JavaTypeDescriptorRepository javaTypeDescriptorRepository; - // todo : hook this map in with the context method to make domain types... - private final Map domainModelTypes - = new HashMap(); - private final StandardAssociationRelationalBindingResolverImpl standardAssociationRelationalBindingResolver; private final MappedByAssociationRelationalBindingResolverImpl mappedByAssociationRelationalBindingResolver; private final Map entityCacheRegionDefinitionsByEntityName = new HashMap(); - private final Map> identifierDependencyMap = new HashMap>(); public Binder(BindingContext rootBindingContext) { - this.rootBindingContext = new BinderRootContextImpl( rootBindingContext ); + this.eventBus = new BinderEventBus(); + this.sourceIndex = new SourceIndex( rootBindingContext ); + + this.rootBindingContext = new BinderRootContextImpl( rootBindingContext, sourceIndex, eventBus ); this.processHelper = new BinderProcessHelper( this.rootBindingContext ); @@ -257,10 +266,6 @@ public class Binder { public class PreliminarySourceHandlingStep implements BinderStepHierarchyStrategy { @Override public void visit(EntityHierarchySource source, BinderLocalBindingContext context) { - entityHierarchiesByRootEntityName.put( - source.getRoot().getEntityName(), - source - ); sourceIndex.indexHierarchy( source ); final HierarchyDetails hierarchyDetails = createHierarchyDetails( source ); @@ -568,27 +573,27 @@ public class Binder { final JavaTypeDescriptor javaTypeDescriptor = javaTypeDescriptorRepository.getType( descriptorTypeName ); if ( EntitySource.class.isInstance( source ) ) { - Entity entityDomainType = (Entity) domainModelTypes.get( javaTypeDescriptor ); + Entity entityDomainType = (Entity) localBindingContext().locateDomainType( javaTypeDescriptor ); if ( entityDomainType == null ) { - entityDomainType = new Entity( + entityDomainType = localBindingContext().buildEntityDomainType( javaTypeDescriptor, resolveDomainType( source.getSuperType() ) ); - domainModelTypes.put( javaTypeDescriptor, entityDomainType ); } return entityDomainType; } else { - MappedSuperclass superDomainType = (MappedSuperclass) domainModelTypes.get( javaTypeDescriptor ); + MappedSuperclass superDomainType = (MappedSuperclass) localBindingContext().locateDomainType( + javaTypeDescriptor + ); if ( superDomainType == null ) { - superDomainType = new MappedSuperclass( + superDomainType = localBindingContext().buildMappedSuperclassDomainType( javaTypeDescriptor, resolveDomainType( source.getSuperType() ) ); - domainModelTypes.put( javaTypeDescriptor, superDomainType ); } return superDomainType; @@ -642,6 +647,8 @@ public class Binder { // (and no formulas) contained in a defined unique key that only contains these columns. // if so, mark the many-to-one as a logical one-to-one. // TODO: when does this have to be done. + + eventBus.finishUpAttributes(); } private BinderStepHierarchyStrategy bindIdentifierGeneratorExecutor() { @@ -654,21 +661,21 @@ public class Binder { } private void applyToAllEntityHierarchies(BinderStepHierarchyStrategy strategy) { - processHelper.apply( entityHierarchiesByRootEntityName.values(), strategy ); + processHelper.apply( sourceIndex.getAllHierarchySources(), strategy ); } private void applyToAllEntityHierarchies(BinderStepEntityStrategy strategy) { - processHelper.apply( entityHierarchiesByRootEntityName.values(), strategy ); + processHelper.apply( sourceIndex.getAllHierarchySources(), strategy ); } private void applyToAllEntityHierarchies(BinderStepCombinedStrategy strategy) { - processHelper.apply( entityHierarchiesByRootEntityName.values(), strategy ); + processHelper.apply( sourceIndex.getAllHierarchySources(), strategy ); } private void applyToAllEntityHierarchies( BinderStepHierarchyStrategy hierarchyStrategy, BinderStepEntityStrategy entityStrategy) { - processHelper.apply( entityHierarchiesByRootEntityName.values(), hierarchyStrategy, entityStrategy ); + processHelper.apply( sourceIndex.getAllHierarchySources(), hierarchyStrategy, entityStrategy ); } private BinderStepEntityStrategy resolveAssociationSourcesExecutor() { @@ -682,6 +689,10 @@ public class Binder { public void visit(EntitySource source, BinderLocalBindingContext context) { sourceIndex.resolveAssociationSources( source, context ); } + + @Override + public void afterAllEntitiesInHierarchy() { + } }; } @@ -721,437 +732,21 @@ public class Binder { } private void bindEntityHierarchiesExcludingNonIdAttributeBindings() { - final BinderStepCombinedStrategy strategy = new BinderStepCombinedStrategy() { - @Override - public void visit(EntityHierarchySource source, BinderLocalBindingContext context) { - final HierarchyDetails binding = context.locateBinding( source ); - bindIdentifier( binding, source ); - bindSecondaryTables( binding.getRootEntityBinding(), source.getRoot() ); - } - - @Override - public boolean applyToRootEntity() { - return false; - } - - @Override - public void visit(EntitySource source, BinderLocalBindingContext context) { - final EntityBinding binding = context.locateBinding( source ); - bindSubEntityPrimaryKey( binding, source ); - bindSecondaryTables( binding, source ); - markSuperEntityTableAbstractIfNecessary( binding.getSuperEntityBinding() ); - } - - private void bindSecondaryTables(EntityBinding entityBinding, EntitySource entitySource) { - for ( final SecondaryTableSource secondaryTableSource : entitySource.getSecondaryTables() ) { - final TableSpecification table = tableHelper().createTable( - secondaryTableSource.getTableSource(), - new TableNamingStrategyHelper( entityBinding ) - ); - table.addComment( secondaryTableSource.getComment() ); - final List joinRelationalValueBindings = getJoinedPrimaryKeyRelationalValueBindings( - entityBinding, - secondaryTableSource.getPrimaryKeyColumnSources(), - table - ); - - // TODO: make the foreign key column the primary key??? - final List targetColumns = foreignKeyHelper() - .determineForeignKeyTargetColumns( entityBinding, secondaryTableSource ); - final ForeignKey foreignKey = locateOrCreateForeignKey( - secondaryTableSource.getExplicitForeignKeyName(), - table, - joinRelationalValueBindings, - foreignKeyHelper().determineForeignKeyTargetTable( entityBinding, secondaryTableSource ), - targetColumns, - secondaryTableSource.isCascadeDeleteEnabled(), - secondaryTableSource.createForeignKeyConstraint() - ); - SecondaryTable secondaryTable = new SecondaryTable( table, foreignKey ); - if ( secondaryTableSource.getFetchStyle()!=null ) { - secondaryTable.setFetchStyle( secondaryTableSource.getFetchStyle() ); - } - secondaryTable.setInverse( secondaryTableSource.isInverse() ); - secondaryTable.setOptional( secondaryTableSource.isOptional() ); - secondaryTable.setCascadeDeleteEnabled( secondaryTableSource.isCascadeDeleteEnabled() ); - secondaryTable.setCustomDelete( secondaryTableSource.getCustomSqlDelete() ); - secondaryTable.setCustomInsert( secondaryTableSource.getCustomSqlInsert() ); - secondaryTable.setCustomUpdate( secondaryTableSource.getCustomSqlUpdate() ); - entityBinding.addSecondaryTable( secondaryTable ); - rootBindingContext.getMetadataCollector().addSecondaryTable( secondaryTable ); - } - } - - private void bindIdentifier(HierarchyDetails binding, EntityHierarchySource source) { - final IdentifierSource identifierSource = source.getIdentifierSource(); - final EntityIdentifierNature nature = identifierSource.getNature(); - - switch ( nature ) { - case SIMPLE: { - bindSimpleIdentifier( - binding, - (SimpleIdentifierSource) identifierSource - ); - break; - } - case AGGREGATED_COMPOSITE: { - bindAggregatedCompositeIdentifier( - binding, - (AggregatedCompositeIdentifierSource) identifierSource - ); - break; - } - case NON_AGGREGATED_COMPOSITE: { - bindNonAggregatedCompositeIdentifier( - binding, - (NonAggregatedCompositeIdentifierSource) identifierSource - ); - break; - } - default: { - throw localBindingContext().makeMappingException( "Unknown identifier nature : " + nature.name() ); - } - } - } - - private void bindSimpleIdentifier( - final HierarchyDetails binding, - final SimpleIdentifierSource identifierSource) { - // locate the attribute binding - final SingularAttributeBinding idAttributeBinding = (SingularAttributeBinding) bindIdentifierAttribute( - binding.getRootEntityBinding(), - identifierSource.getIdentifierAttributeSource() - ); - - // Configure ID generator - IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); - if ( generator == null ) { - final Map params = new HashMap(); - params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); - generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); - } - - // determine the unsaved value mapping - final String unsavedValue = interpretIdentifierUnsavedValue( identifierSource, generator ); - - binding.getEntityIdentifier().prepareAsSimpleIdentifier( - idAttributeBinding, - generator, - unsavedValue, - identifierSource.getLookupIdClass(), - propertyAccessorName( identifierSource.getIdClassPropertyAccessorName() ) - ); - - } - - private String interpretIdentifierUnsavedValue( - final IdentifierSource identifierSource, - final IdentifierGeneratorDefinition generator) { - if ( identifierSource == null ) { - throw new IllegalArgumentException( "identifierSource must be non-null." ); - } - if ( generator == null || StringHelper.isEmpty( generator.getStrategy() ) ) { - throw new IllegalArgumentException( "generator must be non-null and its strategy must be non-empty." ); - } - String unsavedValue = null; - if ( identifierSource.getUnsavedValue() != null ) { - unsavedValue = identifierSource.getUnsavedValue(); - } - else if ( "assigned".equals( generator.getStrategy() ) ) { - unsavedValue = "undefined"; - } - else { - switch ( identifierSource.getNature() ) { - case SIMPLE: { - // unsavedValue = null; - break; - } - case NON_AGGREGATED_COMPOSITE: { - // The generator strategy should be "assigned" and processed above. - throw new IllegalStateException( - String.format( - "Expected generator strategy for composite ID: 'assigned'; instead it is: %s", - generator.getStrategy() - ) - ); - } - case AGGREGATED_COMPOSITE: { - // TODO: if the component only contains 1 attribute (when flattened) - // and it is not an association then null should be returned; - // otherwise "undefined" should be returned. - throw new NotYetImplementedException( - String.format( - "Unsaved value for (%s) identifier not implemented yet.", - identifierSource.getNature() - ) - ); - } - default: { - throw new AssertionFailure( - String.format( - "Unexpected identifier nature: %s", - identifierSource.getNature() - ) - ); - } - } - } - return unsavedValue; - } - - private void bindAggregatedCompositeIdentifier( - final HierarchyDetails binding, - final AggregatedCompositeIdentifierSource identifierSource) { - // locate the attribute binding - final EmbeddedAttributeBinding idAttributeBinding = (EmbeddedAttributeBinding) bindIdentifierAttribute( - binding.getRootEntityBinding(), - identifierSource.getIdentifierAttributeSource() - ); - - // Configure ID generator - IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); - if ( generator == null ) { - final Map params = new HashMap(); - params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); - generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); - } - - // determine the unsaved value mapping - final String unsavedValue = interpretIdentifierUnsavedValue( identifierSource, generator ); - - binding.getEntityIdentifier().prepareAsAggregatedCompositeIdentifier( - idAttributeBinding, - generator, - unsavedValue, - identifierSource.getLookupIdClass(), - propertyAccessorName( identifierSource.getIdClassPropertyAccessorName() ) - ); - } - - private void bindNonAggregatedCompositeIdentifier( - final HierarchyDetails binding, - final NonAggregatedCompositeIdentifierSource identifierSource) { - // locate the attribute bindings for the real attributes - final List idAttributeBindings = new ArrayList(); - for ( SingularAttributeSource attributeSource : identifierSource.getAttributeSourcesMakingUpIdentifier() ) { - final SingularAttributeBinding singularAttributeBinding = bindIdentifierAttribute( - binding.getRootEntityBinding(), - attributeSource - ); - idAttributeBindings.add( singularAttributeBinding ); - } - - final Class idClassType = identifierSource.getLookupIdClass(); - final String idClassPropertyAccessorName = idClassType == null - ? null - : propertyAccessorName( identifierSource.getIdClassPropertyAccessorName() ); - - // Configure ID generator - IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); - if ( generator == null ) { - final Map params = new HashMap(); - params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); - generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); - } - // Create the synthetic attribute - final SingularAttribute syntheticAttribute = binding.getRootEntityBinding().getEntity().createSyntheticCompositeAttribute( - SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME, - binding.getRootEntityBinding().getEntity() - ); - - final EmbeddedAttributeBinding syntheticAttributeBinding = binding.getRootEntityBinding() - .makeVirtualCompositeAttributeBinding( - syntheticAttribute, - createMetaAttributeContext( - binding.getRootEntityBinding(), - identifierSource.getToolingHintSources() - ), - idAttributeBindings - ); - - // Create the synthetic attribute binding. - binding.getEntityIdentifier().prepareAsNonAggregatedCompositeIdentifier( - syntheticAttributeBinding, - generator, - interpretIdentifierUnsavedValue( identifierSource, generator ), - idClassType, - idClassPropertyAccessorName - ); - - typeHelper().bindNonAggregatedCompositeIdentifierType( - localBindingContext().getServiceRegistry(), - syntheticAttributeBinding, - syntheticAttribute - ); - } - - private void bindSubEntityPrimaryKey(EntityBinding entityBinding, EntitySource entitySource) { - final InheritanceType inheritanceType = entityBinding.getHierarchyDetails().getInheritanceType(); - final EntityBinding superEntityBinding = entityBinding.getSuperEntityBinding(); - if ( superEntityBinding == null ) { - throw new AssertionFailure( "super entitybinding is null " ); - } - if ( inheritanceType == InheritanceType.JOINED ) { - JoinedSubclassEntitySource subclassEntitySource = (JoinedSubclassEntitySource) entitySource; - final List columnSources = subclassEntitySource.getPrimaryKeyColumnSources(); - final TableSpecification table = entityBinding.getPrimaryTable(); - final List joinRelationalValueBindings = - getJoinedPrimaryKeyRelationalValueBindings( superEntityBinding, columnSources, table ); - - entityBinding.setKeyRelationalValueBindings( joinRelationalValueBindings ); - List targetColumns = - foreignKeyHelper().determineForeignKeyTargetColumns( - superEntityBinding, - subclassEntitySource - ); - - ForeignKey foreignKey = locateOrCreateForeignKey( - subclassEntitySource.getExplicitForeignKeyName(), - table, - joinRelationalValueBindings, - foreignKeyHelper().determineForeignKeyTargetTable( - superEntityBinding, - subclassEntitySource - ), - targetColumns, - subclassEntitySource.isCascadeDeleteEnabled(), - subclassEntitySource.createForeignKeyConstraint() - ); - - if ( subclassEntitySource.isCascadeDeleteEnabled() ) { - entityBinding.setCascadeDeleteEnabled( true ); - } - } - } - - private void markSuperEntityTableAbstractIfNecessary(EntityBinding superEntityBinding) { - if ( superEntityBinding == null ) { - return; - } - if ( superEntityBinding.getHierarchyDetails().getInheritanceType() != InheritanceType.TABLE_PER_CLASS ) { - return; - } - if ( superEntityBinding.isAbstract() != Boolean.TRUE ) { - return; - } - if ( !Table.class.isInstance( superEntityBinding.getPrimaryTable() ) ) { - return; - } - Table.class.cast( superEntityBinding.getPrimaryTable() ).setPhysicalTable( false ); - } - }; - - // TODO: need to determine the proper order for processing EntityHierarchySource objects - // so that dependent EntityHierarchySource is processed after the EntityHierarchySource it - // is dependent on. - // For now, just delay processing the dependent entity hierarchies. - final Set unresolvedEntityHierarchies = new HashSet(); - for ( final EntityHierarchySource entityHierarchySource : entityHierarchiesByRootEntityName.values() ) { - if ( isIdentifierDependentOnOtherEntityHierarchy( entityHierarchySource ) ) { - unresolvedEntityHierarchies.add( entityHierarchySource ); - } - else { - processHelper.apply( entityHierarchySource, strategy ); - } + // unlike most of the other "steps" in the Binder, here we create an + // instance per hierarchy; the reason being that it is easier to fire + // notifications of the identifier being completely bound this way. + for ( final EntityHierarchySource entityHierarchySource : sourceIndex.getAllHierarchySources() ) { + final BinderStepCombinedStrategy strategy = new IdentifierAndSecondaryTableBindingStep( entityHierarchySource ); + processHelper.apply( entityHierarchySource, strategy ); } - // The following is to try to resolve any dependent entity hierarchies. - // It runs through all the dependent entity hierarchies and resolves what it can. - // This process repeats until no more can be resolved. - // TODO: this will not be necessary once we know the proper order for - // processing entity hierarchies. - int oldSize = Integer.MAX_VALUE; - while( !unresolvedEntityHierarchies.isEmpty() && unresolvedEntityHierarchies.size() < oldSize ) { - LOG.debug( - String.format( - "Retry resolving remaining unresolved EntityHieraries: %s", - getRootEntityNames( unresolvedEntityHierarchies ) - ) - ); - oldSize = unresolvedEntityHierarchies.size(); - for ( Iterator it = unresolvedEntityHierarchies.iterator(); it.hasNext(); ) { - final EntityHierarchySource entityHierarchySource = it.next(); - try { - processHelper.apply( entityHierarchySource, strategy ); - // succeeded, so the entityHierarchySource is no longer unresolved. - it.remove(); - LOG.debug( - String.format( - "EntityHierarchy [%s] has been resolved", entityHierarchySource.getRoot().getEntityName() - ) - ); - } - catch (Exception ex) { - // just log the exception. - LOG.debug( - String.format( - "Could not resolve EntityHierarchy %s due to: [%s]", - entityHierarchySource.getRoot().getEntityName(), - ex - ) - ); - } - } - } - // If any entity hierarchies cannot be resolved, then throw exception. - if ( ! unresolvedEntityHierarchies.isEmpty() ) { - throw new IllegalStateException( - "Could not resolve all EntityHierarchies; remaining = {" + - getRootEntityNames( unresolvedEntityHierarchies ) + - "}" - ); - } + eventBus.finishUpIdentifiers(); } - private String getRootEntityNames(Set entityHierarchySources) { - StringBuilder buffer = new StringBuilder(); - String sep = ""; - for ( EntityHierarchySource entityHierarchySource : entityHierarchySources ) { - buffer.append( sep ).append( entityHierarchySource.getRoot().getEntityName() ); - sep = ", "; - } - return buffer.toString(); - } - - // TODO: this will not be necessary once we know the proper order for - // processing entity hierarchies. - private boolean isIdentifierDependentOnOtherEntityHierarchy(EntityHierarchySource entityHierarchySource) { - final EntitySource rootEntitySource = entityHierarchySource.getRoot(); - final IdentifierSource identifierSource = entityHierarchySource.getIdentifierSource(); - if ( identifierSource.getNature() != EntityIdentifierNature.SIMPLE ) { - final List subAttributeSources; - if ( identifierSource.getNature() == EntityIdentifierNature.AGGREGATED_COMPOSITE ) { - subAttributeSources = ( (AggregatedCompositeIdentifierSource) identifierSource ).getIdentifierAttributeSource().getEmbeddableSource().attributeSources(); - } - else { - subAttributeSources = ( (NonAggregatedCompositeIdentifierSource) identifierSource ).getAttributeSourcesMakingUpIdentifier(); - } - return containsSingularAssociation( subAttributeSources ); - } - else { - final SimpleIdentifierSource simpleIdentifierSource = (SimpleIdentifierSource) identifierSource; - return simpleIdentifierSource.getIdentifierAttributeSource().getSingularAttributeNature() != SingularAttributeNature.BASIC; - } - } - - // TODO: this will not be necessary once we know the proper order for - // processing entity hierarchies. - private boolean containsSingularAssociation(List subAttributeSources) { - for ( AttributeSource attributeSource : subAttributeSources ) { - SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource; - // If the attribute source is for a -to-one association, the nature may not be resolved yet. - if ( ToOneAttributeSource.class.isInstance( singularAttributeSource ) ) { - return true; - } - else if ( ( (SingularAttributeSource) attributeSource ).getSingularAttributeNature() == SingularAttributeNature.COMPOSITE ) { - EmbeddedAttributeSource embeddedAttributeSource = (EmbeddedAttributeSource) attributeSource; - return containsSingularAssociation( embeddedAttributeSource.getEmbeddableSource().attributeSources() ); - } - } - return false; - } - - private AttributeBindingContainer locateAttributeBindingContainer(final EntityBinding entityBinding, final String containerPath) { + public static AttributeBindingContainer locateAttributeBindingContainer( + EntityBinding entityBinding, + String containerPath, + BinderRootContext context) { if ( StringHelper.isEmpty( containerPath ) ) { return entityBinding; } @@ -1164,7 +759,7 @@ public class Binder { return ( (EmbeddedAttributeBinding) attributeBinding ).getEmbeddableBinding(); } - throw localBindingContext().makeMappingException( + throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext().makeMappingException( "Could not determine how to treat resolved attribute binding [" + attributeBinding + "] as AttributeBindingContainer" ); @@ -1183,7 +778,10 @@ public class Binder { public void visit(EntitySource source, BinderLocalBindingContext context) { final EntityBinding binding = context.locateBinding( source ); bindSingularAttributes( binding, isMappedBy, singularAttributeNature ); + } + @Override + public void afterAllEntitiesInHierarchy() { } }; } @@ -1208,7 +806,11 @@ public class Binder { ? "" : attributeSource.getAttributePath().getParent().getFullPath(); - final AttributeBindingContainer attributeBindingContainer = locateAttributeBindingContainer( entityBinding, containerPath ); + final AttributeBindingContainer attributeBindingContainer = locateAttributeBindingContainer( + entityBinding, + containerPath, + rootBindingContext + ); if ( isMappedBy ) { if ( !ToOneAttributeSource.class.isInstance( attributeSource ) ) { throw new AssertionFailure( @@ -1352,7 +954,7 @@ public class Binder { ? "" : attributeSource.getAttributePath().getParent().getFullPath(); final AttributeBindingContainer attributeBindingContainer = - locateAttributeBindingContainer( entityBinding, containerPath ); + locateAttributeBindingContainer( entityBinding, containerPath, rootBindingContext ); bindAttribute( attributeBindingContainer, attributeSource ); @@ -1373,6 +975,10 @@ public class Binder { } } } + + @Override + public void afterAllEntitiesInHierarchy() { + } }; } @@ -1410,24 +1016,37 @@ public class Binder { } } } + + @Override + public void afterAllEntitiesInHierarchy() { + } }; } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Entity binding relates methods + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Entity binding related methods - private EntityBinding locateEntityBinding( + private static String determineReferencedEntityName( final JavaTypeDescriptor referencedEntityTypeDescriptor, final String explicitEntityName) { - final String referencedEntityName; if ( explicitEntityName != null ) { - referencedEntityName = explicitEntityName; + return explicitEntityName; } else if ( referencedEntityTypeDescriptor != null ) { - referencedEntityName = referencedEntityTypeDescriptor.getName().toString(); + return referencedEntityTypeDescriptor.getName().toString(); } else { throw new IllegalArgumentException( "explicitEntityName and entityJavaClassReference cannot both be null." ); } + } + + private EntityBinding locateEntityBinding( + final JavaTypeDescriptor referencedEntityTypeDescriptor, + final String explicitEntityName) { + final String referencedEntityName = determineReferencedEntityName( + referencedEntityTypeDescriptor, + explicitEntityName + ); return locateEntityBinding( referencedEntityName ); } @@ -1634,14 +1253,25 @@ public class Binder { joinRelationalValueBindings.add( new RelationalValueBinding( table, column, true, false ) ); } } - typeHelper().bindJdbcDataType( - entityBinding.getHierarchyDetails() - .getEntityIdentifier() - .getAttributeBinding() - .getHibernateTypeDescriptor() - .getResolvedTypeMapping(), - joinRelationalValueBindings - ); + + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); + + final Type idType; + if ( idInfo.getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final NonAggregatedCompositeIdentifierBinding idBinding = + (NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + idType = idBinding.getHibernateType( + localBindingContext().getServiceRegistry(), + localBindingContext().getMetadataCollector().getTypeResolver().getTypeFactory() + ); + } + else { + final EntityIdentifier.AttributeBasedIdentifierBinding idBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + idType = idBinding.getAttributeBinding().getHibernateTypeDescriptor().getResolvedTypeMapping(); + } + + typeHelper().bindJdbcDataType( idType, joinRelationalValueBindings ); return joinRelationalValueBindings; } @@ -1820,6 +1450,7 @@ public class Binder { return attributeBinding; } + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ singular attributes binding private SingularAttributeBinding bindSingularAttribute( final AttributeBindingContainer attributeBindingContainer, @@ -2015,18 +1646,18 @@ public class Binder { attribute.resolveType( referencedEntityBinding.getEntity() ); } - if ( referencedAttributeBinding != referencedEntityBinding.getHierarchyDetails() - .getEntityIdentifier() - .getAttributeBinding() ) { - referencedAttributeBinding.setAlternateUniqueKey( true ); + String uniqueKeyAttributeName = null; + final EntityIdentifier idInfo = referencedEntityBinding.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final EntityIdentifier.AttributeBasedIdentifierBinding idBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final SingularAttributeBinding idAttrBinding = idBinding.getAttributeBinding(); + if ( referencedAttributeBinding != idAttrBinding ) { + referencedAttributeBinding.setAlternateUniqueKey( true ); + uniqueKeyAttributeName = referencedAttributeBinding.getAttributePath().getFullPath(); + } } - final SingularAttributeBinding idAttributeBinding = - referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - final String uniqueKeyAttributeName = idAttributeBinding == referencedAttributeBinding - ? null - : referencedAttributeBinding.getAttributePath().getFullPath(); - final Type resolvedType = rootBindingContext.getMetadataCollector().getTypeResolver().getTypeFactory().manyToOne( referencedEntityBinding.getEntityName(), uniqueKeyAttributeName == null, @@ -2121,16 +1752,19 @@ public class Binder { attribute.resolveType( referencedEntityBinding.getEntity() ); } - final String uniqueKeyAttributeName; - final AttributeBinding referencedEntityIdAttributeBinding = - referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - if ( referencedEntityIdAttributeBinding == referencedAttributeBinding || - referencedAttributeBinding.getRelationalValueBindings().isEmpty()) { - uniqueKeyAttributeName = null; - } - else { - uniqueKeyAttributeName = referencedAttributeBinding.getAttributePath().getFullPath(); + + String uniqueKeyAttributeName = null; + final EntityIdentifier idInfo = referencedEntityBinding.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final EntityIdentifier.AttributeBasedIdentifierBinding idBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final SingularAttributeBinding idAttrBinding = idBinding.getAttributeBinding(); + if ( referencedAttributeBinding != idAttrBinding ) { + referencedAttributeBinding.setAlternateUniqueKey( true ); + uniqueKeyAttributeName = referencedAttributeBinding.getAttributePath().getFullPath(); + } } + final Type resolvedType; if ( attributeSource.isMappedBy() || attributeSource.relationalValueSources().isEmpty() ) { resolvedType = rootBindingContext.getMetadataCollector().getTypeResolver().getTypeFactory().oneToOne( @@ -2177,11 +1811,6 @@ public class Binder { private void bindToOneDetails( final ToOneAttributeSource attributeSource, final SingularAssociationAttributeBinding attributeBinding) { - final SingularAttributeBinding idAttributeBinding = - attributeBinding.getReferencedEntityBinding().getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - if ( attributeBinding.getReferencedAttributeBinding() != idAttributeBinding ) { - attributeBinding.getReferencedAttributeBinding().setAlternateUniqueKey( true ); - } attributeBinding.setCascadeStyle( determineCascadeStyle( attributeSource.getCascadeStyles() ) ); attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); @@ -2477,11 +2106,10 @@ public class Binder { } private Aggregate findOrBuildAggregate(JavaTypeDescriptor embeddableDescriptor) { - org.hibernate.metamodel.spi.domain.Type domainType = domainModelTypes.get( embeddableDescriptor ); - if ( domainType == null ) { - domainType = new Aggregate( embeddableDescriptor, null ); - domainModelTypes.put( embeddableDescriptor, domainType ); - } + org.hibernate.metamodel.spi.domain.Type domainType = localBindingContext().locateOrBuildDomainType( + embeddableDescriptor, + true + ); if ( !Aggregate.class.isInstance( domainType ) ) { throw new IllegalStateException( @@ -3256,14 +2884,26 @@ public class Binder { } - private String propertyAccessorName(final AttributeSource attributeSource) { - return propertyAccessorName( attributeSource.getPropertyAccessorName() ); + private String propertyAccessorName(AttributeSource attributeSource) { + return propertyAccessorName( attributeSource.getPropertyAccessorName(), rootBindingContext ); } - private String propertyAccessorName(final String propertyAccessorName) { - return propertyAccessorName == null - ? localBindingContext().getMappingDefaults().getPropertyAccessorName() - : propertyAccessorName; + public static String propertyAccessorName(AttributeSource attributeSource, BinderRootContext context) { + return propertyAccessorName( attributeSource.getPropertyAccessorName(), context ); + } + + private String propertyAccessorName(String propertyAccessorName) { + return propertyAccessorName( propertyAccessorName, rootBindingContext ); + } + + public static String propertyAccessorName(String propertyAccessorName, BinderRootContext context) { + if ( propertyAccessorName != null ) { + return propertyAccessorName; + } + + return context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() + .getMappingDefaults() + .getPropertyAccessorName(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static methods @@ -3357,13 +2997,13 @@ public class Binder { return cascadeStyleResult; } - private static MetaAttributeContext createMetaAttributeContext( + public static MetaAttributeContext createMetaAttributeContext( final AttributeBindingContainer attributeBindingContainer, final AttributeSource attributeSource) { return createMetaAttributeContext( attributeBindingContainer, attributeSource.getToolingHintSources() ); } - private static MetaAttributeContext createMetaAttributeContext( + public static MetaAttributeContext createMetaAttributeContext( final AttributeBindingContainer attributeBindingContainer, final Iterable metaAttributeSources) { return createMetaAttributeContext( @@ -3373,7 +3013,7 @@ public class Binder { ); } - private static MetaAttributeContext createMetaAttributeContext( + public static MetaAttributeContext createMetaAttributeContext( final Iterable metaAttributeSources, final boolean onlyInheritable, final MetaAttributeContext parentContext) { @@ -3393,17 +3033,1717 @@ public class Binder { return subContext; } - private static SingularAttribute createSingularAttribute( - final AttributeBindingContainer attributeBindingContainer, - final SingularAttributeSource attributeSource) { - return attributeSource.isVirtualAttribute() ? - attributeBindingContainer.getAttributeContainer().createSyntheticSingularAttribute( - attributeSource.getName() - ) : - attributeBindingContainer.getAttributeContainer().createSingularAttribute( attributeSource.getName() ); - } - public static interface DefaultNamingStrategy { String defaultName(NamingStrategy namingStrategy); } + + protected static SingularAttribute createSingularAttribute( + AttributeBindingContainer attributeBindingContainer, + SingularAttributeSource attributeSource) { + return attributeSource.isVirtualAttribute() + ? attributeBindingContainer.getAttributeContainer() + .createSyntheticSingularAttribute( attributeSource.getName() ) + : attributeBindingContainer.getAttributeContainer() + .createSingularAttribute( attributeSource.getName() ); + } + + + public static String interpretIdentifierUnsavedValue( + final IdentifierSource identifierSource, + final IdentifierGeneratorDefinition generator) { + if ( identifierSource == null ) { + throw new IllegalArgumentException( "identifierSource must be non-null." ); + } + if ( generator == null || StringHelper.isEmpty( generator.getStrategy() ) ) { + throw new IllegalArgumentException( "generator must be non-null and its strategy must be non-empty." ); + } + String unsavedValue = null; + if ( identifierSource.getUnsavedValue() != null ) { + unsavedValue = identifierSource.getUnsavedValue(); + } + else if ( "assigned".equals( generator.getStrategy() ) ) { + unsavedValue = "undefined"; + } + else { + switch ( identifierSource.getNature() ) { + case SIMPLE: { + // unsavedValue = null; + break; + } + case NON_AGGREGATED_COMPOSITE: { + // The generator strategy should be "assigned" and processed above. + throw new IllegalStateException( + String.format( + "Expected generator strategy for composite ID: 'assigned'; instead it is: %s", + generator.getStrategy() + ) + ); + } + case AGGREGATED_COMPOSITE: { + // TODO: if the component only contains 1 attribute (when flattened) + // and it is not an association then null should be returned; + // otherwise "undefined" should be returned. + throw new NotYetImplementedException( + String.format( + "Unsaved value for (%s) identifier not implemented yet.", + identifierSource.getNature() + ) + ); + } + default: { + throw new AssertionFailure( + String.format( + "Unexpected identifier nature: %s", + identifierSource.getNature() + ) + ); + } + } + } + return unsavedValue; + } + + + + + + + + + + + + + + + + + + + /** + * The naming here is probably backwards... + * + * Represents a process within a binding step. + */ + private static interface Process { + public boolean doProcess(); + + public void addFollowOnProcess(Process followOn); + } + + private static abstract class AbstractProcess implements Process { + private List followOnProcesses; + + @Override + public final void addFollowOnProcess(Process followOn) { + if ( followOnProcesses == null ) { + followOnProcesses = new ArrayList(); + } + followOnProcesses.add( followOn ); + } + + protected void doFollowOnProcesses() { + if ( followOnProcesses == null ) { + return; + } + + for ( Process followOnProcess : followOnProcesses ) { + followOnProcess.doProcess(); + } + followOnProcesses.clear(); + } + } + + private static abstract class AbstractNoFollowOnProcess implements Process { + @Override + public final void addFollowOnProcess(Process followOn) { + throw new IllegalStateException( "Follow on processes not allowed here" ); + } + } + + private static interface IdentifierBinder extends Process { + } + + private static abstract class AbstractIdentifierBinder extends AbstractProcess implements IdentifierBinder { + protected final HierarchyDetails binding; + protected final BinderLocalBindingContext context; + + protected AbstractIdentifierBinder( + HierarchyDetails binding, + BinderLocalBindingContext context) { + this.binding = binding; + this.context = context; + } + + protected String determineReferencedEntityName(ToOneAttributeSource toOneAttributeSource) { + final JavaTypeDescriptor referencedEntityTypeDescriptor = context.typeHelper().determineJavaType( + toOneAttributeSource, + binding.getRootEntityBinding().getAttributeContainer() + ); + return Binder.determineReferencedEntityName( + referencedEntityTypeDescriptor, + toOneAttributeSource.getReferencedEntityName() + ); + } + + protected boolean isIdentifierFullyBound(String referencedEntityName) { + final EntityBinding referencedEntityBinding = context.getMetadataCollector() + .getEntityBinding( referencedEntityName ); + if ( referencedEntityBinding == null ) { + return false; + } + + return referencedEntityBinding.getHierarchyDetails() + .getEntityIdentifier() + .isBound(); + } + + protected void afterBindingComplete() { + doFollowOnProcesses(); + } + } + + /** + * Binder step for binding identifiers, pks and secondary tables across + * an entity hierarchy. + */ + private class IdentifierAndSecondaryTableBindingStep implements BinderStepCombinedStrategy { + private final EntityHierarchySource source; + private final HierarchyDetails binding; + + private IdentifierBinder pendingIdentifierBinder; + + private IdentifierAndSecondaryTableBindingStep(EntityHierarchySource source) { + this.source = source; + this.binding = rootBindingContext.locateBinding( source ); + } + + @Override + public void visit(EntityHierarchySource source, BinderLocalBindingContext context) { + if ( source != this.source ) { + return; + } + + // Build an id binder, and ask it to process the binding + final IdentifierBinder idBinder = makeIdentifierBinder( binding, source, context ); + idBinder.addFollowOnProcess( + new AbstractNoFollowOnProcess() { + final EntityBinding rootEntityBinding = binding.getRootEntityBinding(); + final EntitySource rootEntitySource = IdentifierAndSecondaryTableBindingStep.this.source.getRoot(); + @Override + public boolean doProcess() { + bindSecondaryTables( rootEntityBinding, rootEntitySource ); + return false; + } + } + ); + final boolean delayed = !idBinder.doProcess(); + if ( delayed ) { + // the binding we not able to be processed yet, delay it and + // keep the binder reference around to register follow-ons as + // needed. + // + // the binder should have registered itself as a listener with + // the event bus for any events it is waiting on + pendingIdentifierBinder = idBinder; + } + } + + private IdentifierBinder makeIdentifierBinder( + HierarchyDetails binding, + EntityHierarchySource source, + BinderLocalBindingContext context) { + final IdentifierSource identifierSource = source.getIdentifierSource(); + final EntityIdentifierNature nature = identifierSource.getNature(); + + switch ( nature ) { + case SIMPLE: { + return new SimpleIdentifierBinder( binding, (SimpleIdentifierSource) identifierSource, context ); + } + case AGGREGATED_COMPOSITE: { + return new AggregatedCompositeIdentifierBinder( + binding, + (AggregatedCompositeIdentifierSource) identifierSource, + context + ); + } + case NON_AGGREGATED_COMPOSITE: { + return new NonAggregatedCompositeIdentifierBinder( + binding, + (NonAggregatedCompositeIdentifierSource) identifierSource, + context + ); + } + default: { + throw localBindingContext().makeMappingException( "Unknown identifier nature : " + nature.name() ); + } + } + } + + /** + * Binder for binding simple (single basic or to-one attribute) identifiers + */ + private class SimpleIdentifierBinder extends AbstractIdentifierBinder { + protected final SimpleIdentifierSource identifierSource; + + public SimpleIdentifierBinder( + HierarchyDetails binding, + SimpleIdentifierSource identifierSource, + BinderLocalBindingContext context) { + super( binding, context ); + + this.identifierSource = identifierSource; + } + + @Override + public boolean doProcess() { + // opt out of completing the process if we cannot... + final SingularAttributeSource attributeSource = identifierSource.getIdentifierAttributeSource(); + if ( attributeSource.getSingularAttributeNature() == SingularAttributeNature.MANY_TO_ONE + || attributeSource.getSingularAttributeNature() == SingularAttributeNature.ONE_TO_ONE ) { + final ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) attributeSource; + final String referencedEntityName = determineReferencedEntityName( toOneAttributeSource ); + if ( !isIdentifierFullyBound( referencedEntityName ) ) { + delayBinding( binding, referencedEntityName ); + return false; + } + } + + completeBinding(); + return true; + } + + private void delayBinding(final HierarchyDetails hierarchyDetails, final String referencedEntityName) { + context.getEventBus().addIdentifierBindingListener( + new IdentifierBindingListener() { + @Override + public boolean identifierResolved(HierarchyDetails resolvingHierarchyDetails) { + if ( hierarchyDetails == resolvingHierarchyDetails ) { + // avoid cycle + return false; + } + + if ( isIdentifierFullyBound( referencedEntityName ) ) { + // complete the binding, and tell the event bus to + // remove us as a listener + completeBinding(); + return true; + } + return false; + } + } + ); + } + + private boolean inCompletion = false; + + private void completeBinding() { + // avoid cycle + if ( inCompletion ) { + return; + } + + inCompletion = true; + + final SingularAttributeBinding idAttributeBinding = bindIdentifierAttribute( + binding.getRootEntityBinding(), + identifierSource.getIdentifierAttributeSource() + ); + + // Configure ID generator + IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); + if ( generator == null ) { + final Map params = new HashMap(); + params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); + generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); + } + + // determine the unsaved value mapping + final String unsavedValue = interpretIdentifierUnsavedValue( identifierSource, generator ); + + binding.getEntityIdentifier().prepareAsSimpleIdentifier( + idAttributeBinding, + generator, + unsavedValue + ); + + afterBindingComplete(); + } + + } + + private class AggregatedCompositeIdentifierBinder extends AbstractIdentifierBinder { + private final AggregatedCompositeIdentifierSource identifierSource; + + public AggregatedCompositeIdentifierBinder( + HierarchyDetails binding, + AggregatedCompositeIdentifierSource identifierSource, + BinderLocalBindingContext context) { + super( binding, context ); + + this.identifierSource = identifierSource; + } + + @Override + public boolean doProcess() { + final Set pendingEntityNames = new HashSet(); + + collectPendingEntityNames( pendingEntityNames, identifierSource.getIdentifierAttributeSource() ); + + for ( MapsIdSource mapsIdSource : identifierSource.getMapsIdSources() ) { + final ToOneAttributeSource toOneAttributeSource = mapsIdSource.getAssociationAttributeSource(); + final String referencedEntityName = determineReferencedEntityName( toOneAttributeSource ); + if ( !isIdentifierFullyBound( referencedEntityName ) ) { + pendingEntityNames.add( referencedEntityName ); + } + } + + if ( !pendingEntityNames.isEmpty() ) { + delayBinding( binding, pendingEntityNames ); + return false; + } + + completeBinding(); + return true; + } + + private void collectPendingEntityNames( + Set pendingEntityNames, + EmbeddedAttributeSource embeddedAttributeSource) { + for ( AttributeSource attributeSource : + embeddedAttributeSource.getEmbeddableSource().attributeSources() ) { + final SingularAttributeSource sas = (SingularAttributeSource) attributeSource; + if ( sas.getSingularAttributeNature() == SingularAttributeNature.MANY_TO_ONE + || sas.getSingularAttributeNature() == SingularAttributeNature.ONE_TO_ONE ) { + final ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) sas; + final String referencedEntityName = determineReferencedEntityName( toOneAttributeSource ); + if ( !isIdentifierFullyBound( referencedEntityName ) ) { + pendingEntityNames.add( referencedEntityName ); + } + } + else if ( sas.getSingularAttributeNature() == SingularAttributeNature.COMPOSITE ) { + collectPendingEntityNames( pendingEntityNames, (EmbeddedAttributeSource) sas ); + } + } + } + + private void delayBinding(final HierarchyDetails hierarchyDetails, final Set names) { + context.getEventBus().addIdentifierBindingListener( + new IdentifierBindingListener() { + private final Set pendingEntityNames = names; + @Override + public boolean identifierResolved(HierarchyDetails resolvingHierarchyDetails) { + if ( hierarchyDetails == resolvingHierarchyDetails ) { + // avoid cycle + return false; + } + + final Iterator itr = pendingEntityNames.iterator(); + while ( itr.hasNext() ) { + final String pendingEntityName = itr.next(); + if ( isIdentifierFullyBound( pendingEntityName ) ) { + itr.remove(); + } + } + if ( pendingEntityNames.isEmpty() ) { + // complete the binding, and tell the event bus to + // remove us as a listener + completeBinding(); + return true; + } + + return false; + } + } + ); + } + + + private boolean inCompletion = false; + + private void completeBinding() { + // avoid cycle + if ( inCompletion ) { + return; + } + + inCompletion = true; + + final EmbeddedAttributeSource cidAttrSource = identifierSource.getIdentifierAttributeSource(); + + // Process any associations annotated as @MapsId, adding them + // to a Map keyed by the name of the id attribute they map.. + // we'll use this info later when binding the pk class attributes + final Map mapsIdMap = + new HashMap(); + for ( MapsIdSource mapsIdSource : identifierSource.getMapsIdSources() ) { + final SingularAttributeBinding attrBinding = bindIdentifierAttribute( + binding.getRootEntityBinding(), + mapsIdSource.getAssociationAttributeSource() + ); + mapsIdMap.put( + mapsIdSource.getMappedIdAttributeName(), + (SingularAssociationAttributeBinding) attrBinding + ); + } + + // Resolve the domain definition of the PK class + final JavaTypeDescriptor pkClassTypeDescriptor = determinePkClassTypeDescriptor( + binding.getRootEntityBinding(), + identifierSource + ); + final Aggregate pkClass = (Aggregate) localBindingContext().locateOrBuildDomainType( + pkClassTypeDescriptor, + true + ); + + + // `pkAttribute` is the (domain) attribute reference for the @EmbeddedId attribute + SingularAttribute pkAttribute = binding.getRootEntityBinding() + .getEntity() + .locateCompositeAttribute( cidAttrSource.getName() ); + if ( pkAttribute == null ) { + pkAttribute = binding.getRootEntityBinding().getEntity() + .createSingularAttribute( cidAttrSource.getName() ); + pkAttribute.resolveType( pkClass ); + } + + // Handle any `parent` reference + SingularAttribute pkClassParentAttribute = null; + if ( cidAttrSource.getEmbeddableSource().getParentReferenceAttributeName() != null ) { + pkClassParentAttribute = pkClass.createSingularAttribute( + cidAttrSource.getEmbeddableSource().getParentReferenceAttributeName() + ); + } + + // Handle custom tuplizer + Class customTuplizer = null; + if ( cidAttrSource.getEmbeddableSource().getExplicitTuplizerClassName() != null ) { + final ClassLoaderService cls = rootBindingContext.getServiceRegistry().getService( ClassLoaderService.class ); + customTuplizer = cls.classForName( cidAttrSource.getEmbeddableSource().getExplicitTuplizerClassName() ); + } + + // Build the attribute binding for the @EmbeddedId attribute; builds the + // EmbeddableBinding implicitly, which we store immediately after as + // `pkClassBinding` + final EmbeddedAttributeBinding idAttributeBinding = binding.getRootEntityBinding().makeAggregatedCompositeAttributeBinding( + pkAttribute, + pkClassParentAttribute, + customTuplizer, + cidAttrSource.getPropertyAccessorName(), + false, + false, + NaturalIdMutability.NOT_NATURAL_ID, + null, + cidAttrSource.getAttributeRole(), + cidAttrSource.getAttributePath() + ); + final EmbeddableBinding pkClassBinding = idAttributeBinding.getEmbeddableBinding(); + + // Now process each attribute in the PK class + for ( AttributeSource attributeSource : cidAttrSource.getEmbeddableSource().attributeSources() ) { + final SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource; + final String attributeName = singularAttributeSource.getName(); + + // Did the attribute have corresponding @MapsId? + final SingularAssociationAttributeBinding correspondingAttribute = mapsIdMap.get( attributeName ); + if ( correspondingAttribute == null ) { + // there was no corresponding @MapsId + final SingularAttributeBinding singularAttributeBinding = bindSingularAttribute( + pkClassBinding, + singularAttributeSource, + true + ); + } + else { + // there was a corresponding @MapsId, grab its + // relational value information + final List relationalValueBindings = new ArrayList(); + for ( RelationalValueBinding relationalValueBinding : correspondingAttribute.getRelationalValueBindings() ) { + final RelationalValueBinding copy; + if ( Column.class.isInstance( relationalValueBinding.getValue() ) ) { + copy = new RelationalValueBinding( + relationalValueBinding.getTable(), + (Column) relationalValueBinding.getValue(), + false, + false + ); + } + else { + copy = new RelationalValueBinding( + relationalValueBinding.getTable(), + (DerivedValue) relationalValueBinding.getValue() + ); + } + relationalValueBindings.add( copy ); + } + final SingularAttributeBinding pkClassAttributeBinding = new BasicAttributeBinding( + pkClassBinding, + pkClass.createSingularAttribute( attributeName ), + relationalValueBindings, + singularAttributeSource.getPropertyAccessorName(), + false, + false, + NaturalIdMutability.NOT_NATURAL_ID, + null, + singularAttributeSource.getAttributeRole(), + singularAttributeSource.getAttributePath(), + PropertyGeneration.NEVER + ); + pkClassAttributeBinding.getHibernateTypeDescriptor().copyFrom( + correspondingAttribute.getReferencedAttributeBinding().getHibernateTypeDescriptor() + ); + } + } + + // Configure ID generator + IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); + if ( generator == null ) { + final Map params = new HashMap(); + params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); + generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); + } + + // determine the unsaved value mapping + final String unsavedValue = interpretIdentifierUnsavedValue( identifierSource, generator ); + + binding.getEntityIdentifier().prepareAsAggregatedCompositeIdentifier( + idAttributeBinding, + generator, + unsavedValue + ); + + typeHelper().bindAggregatedCompositeAttributeType( + localBindingContext().getServiceRegistry(), + true, + pkClass, + pkClass.getDescriptor(), + idAttributeBinding + ); + + afterBindingComplete(); + } + + private JavaTypeDescriptor determinePkClassTypeDescriptor( + EntityBinding rootEntityBinding, + AggregatedCompositeIdentifierSource identifierSource) { + final EmbeddedAttributeSource cidAttrSource = identifierSource.getIdentifierAttributeSource(); + // we can know the pk-class name in one of 2 ways: + // 1) If the composite-id attribute mapping named it as a "target" + if ( cidAttrSource.getEmbeddableSource().getTypeDescriptor() != null ) { + return cidAttrSource.getEmbeddableSource().getTypeDescriptor(); + } + + // 2) so long as the entity is not dynamic (MAP mode), we + // can use reflite on the entity type. + final JavaTypeDescriptor entityType = rootEntityBinding.getEntity().getDescriptor(); + if ( entityType != null ) { + final MemberDescriptor cidAttrDescriptor = findAttributeMemberDescriptor( + entityType, + cidAttrSource.getName() + ); + if ( cidAttrDescriptor == null ) { + throw context.makeMappingException( + "Could not locate aggregated (@EmbeddedId) composite-identifier attribute : " + + cidAttrSource.getAttributeRole().getFullPath() + ); + } + return cidAttrDescriptor.getType().getErasedType(); + } + + throw context.makeMappingException( + "Could not determine aggregated (@EmbeddedId) composite-identifier type : " + + cidAttrSource.getAttributeRole().getFullPath() + ); + } + + private MemberDescriptor findAttributeMemberDescriptor(JavaTypeDescriptor entityType, String name) { + for ( MethodDescriptor methodDescriptor : entityType.getDeclaredMethods() ) { + if ( !AbstractPersistentAttributeMemberResolver.isPersistable( methodDescriptor ) ) { + continue; + } + + final String attributeName = ReflectHelper.getPropertyNameFromGetterMethod( methodDescriptor.getName() ); + + if ( attributeName.equals( name ) ) { + return methodDescriptor; + } + } + + for ( FieldDescriptor fieldDescriptor : entityType.getDeclaredFields() ) { + if ( !AbstractPersistentAttributeMemberResolver.isPersistable( fieldDescriptor ) ) { + continue; + } + + if ( fieldDescriptor.getName().equals( name ) ) { + return fieldDescriptor; + } + } + + if ( ClassDescriptor.class.isInstance( entityType ) ) { + return findAttributeMemberDescriptor( + ( (ClassDescriptor) entityType ).getSuperType(), + name + ); + } + + return null; + } + } + + private class NonAggregatedCompositeIdentifierBinder extends AbstractIdentifierBinder { + private final NonAggregatedCompositeIdentifierSource identifierSource; + + public NonAggregatedCompositeIdentifierBinder( + HierarchyDetails binding, + NonAggregatedCompositeIdentifierSource identifierSource, + BinderLocalBindingContext context) { + super( binding, context ); + this.identifierSource = identifierSource; + } + + @Override + public boolean doProcess() { + final Set pendingEntityNames = new HashSet(); + for ( SingularAttributeSource sas : identifierSource.getAttributeSourcesMakingUpIdentifier() ) { + if ( sas.getSingularAttributeNature() == SingularAttributeNature.MANY_TO_ONE + || sas.getSingularAttributeNature() == SingularAttributeNature.ONE_TO_ONE ) { + final ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) sas; + final String referencedEntityName = determineReferencedEntityName( toOneAttributeSource ); + if ( !isIdentifierFullyBound( referencedEntityName ) ) { + pendingEntityNames.add( referencedEntityName ); + } + } + } + + if ( !pendingEntityNames.isEmpty() ) { + delayBinding( binding, pendingEntityNames ); + return false; + } + + completeBinding(); + return true; + } + + private void delayBinding(final HierarchyDetails hierarchyDetails, final Set names) { + context.getEventBus().addIdentifierBindingListener( + new IdentifierBindingListener() { + private final Set pendingEntityNames = names; + @Override + public boolean identifierResolved(HierarchyDetails resolvingHierarchyDetails) { + if ( hierarchyDetails == resolvingHierarchyDetails ) { + // avoid cycle + return false; + } + final Iterator itr = pendingEntityNames.iterator(); + while ( itr.hasNext() ) { + final String pendingEntityName = itr.next(); + if ( isIdentifierFullyBound( pendingEntityName ) ) { + itr.remove(); + } + } + if ( pendingEntityNames.isEmpty() ) { + // complete the binding, and tell the event bus to + // remove us as a listener + completeBinding(); + return true; + } + + return false; + } + } + ); + } + + + private boolean inCompletion = false; + + private void completeBinding() { + // avoid cycle + if ( inCompletion ) { + return; + } + + inCompletion = true; + + // locate the attribute bindings for the real attributes + final Map attributeBindingMap = new HashMap(); + for ( SingularAttributeSource attributeSource : identifierSource.getAttributeSourcesMakingUpIdentifier() ) { + final SingularAttributeBinding singularAttributeBinding = bindIdentifierAttribute( + binding.getRootEntityBinding(), + attributeSource + ); + attributeBindingMap.put( attributeSource.getName(), singularAttributeBinding ); + } + + // Configure ID generator + IdentifierGeneratorDefinition generator = identifierSource.getIdentifierGeneratorDescriptor(); + if ( generator == null ) { + final Map params = new HashMap(); + params.put( IdentifierGenerator.ENTITY_NAME, binding.getRootEntityBinding().getEntityName() ); + generator = new IdentifierGeneratorDefinition( "default_assign_identity_generator", "assigned", params ); + } + + final EmbeddableBindingImplementor virtualEmbeddableBinding = new AbstractEmbeddableBinding( + binding.getRootEntityBinding(), + binding.getRootEntityBinding().getAttributeContainer(), + binding.getRootEntityBinding().getPrimaryTable(), + binding.getRootEntityBinding().getRoleBase().append( "" ), + binding.getRootEntityBinding().getPathBase().append( "" ), + createMetaAttributeContext( + binding.getRootEntityBinding(), + identifierSource.getToolingHintSources() + ), + null, + null) { + @Override + protected boolean isModifiable() { + return false; + } + + @Override + protected Map attributeBindingMapInternal() { + return attributeBindingMap; + } + + @Override + public boolean isAggregated() { + return false; + } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return binding.getRootEntityBinding().getEntity().getDescriptor(); + } + }; + + final EmbeddableBindingImplementor idClassBinding; + if ( identifierSource.getIdClassSource() != null ) { + final Aggregate component = (Aggregate) localBindingContext().locateOrBuildDomainType( + identifierSource.getIdClassSource().getTypeDescriptor(), + true + ); + idClassBinding = new IdClassEmbeddableBinding( + binding.getRootEntityBinding(), + identifierSource.getIdClassSource(), + component, + virtualEmbeddableBinding + ); + } + else { + idClassBinding = null; + } + + // Create the synthetic attribute + final SingularAttribute virtualAttribute = binding.getRootEntityBinding().getEntity().createSyntheticCompositeAttribute( + SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME, + binding.getRootEntityBinding().getEntity() + ); + + // NOTE : legacy code used the IdClass composite (if one) as: + // 1) virtual id attribute type + // 2) the reported id type of the entity (persister) + final EmbeddedAttributeBinding virtualAttributeBinding = binding.getRootEntityBinding() + .makeVirtualCompositeAttributeBinding( + virtualAttribute, + idClassBinding == null ? virtualEmbeddableBinding : idClassBinding, + createMetaAttributeContext( + binding.getRootEntityBinding(), + identifierSource.getToolingHintSources() + ) + ); + + + + + // Create the synthetic attribute binding. + NonAggregatedCompositeIdentifierBinding idBinding = + binding.getEntityIdentifier().prepareAsNonAggregatedCompositeIdentifier( + virtualEmbeddableBinding, + virtualAttributeBinding, + idClassBinding, + generator, + interpretIdentifierUnsavedValue( identifierSource, generator ) + ); + + // todo : is this needed? The type is implied for both composites here.. + typeHelper().bindNonAggregatedCompositeIdentifierType( + localBindingContext().getServiceRegistry(), + idBinding + ); + + afterBindingComplete(); + } + } + + class IdClassEmbeddableBinding extends AbstractEmbeddableBinding { + private final JavaTypeDescriptor idClassType; + private final Map attributeBindingMap = new HashMap(); + private boolean modifiable = true; + + public IdClassEmbeddableBinding( + EntityBinding rootEntityBinding, + EmbeddableSource idClassSource, + Aggregate composite, + EmbeddableBindingImplementor virtualIdentifierComposite) { + super( + rootEntityBinding, + composite, + rootEntityBinding.getPrimaryTable(), + new AttributeRole( idClassSource.getTypeDescriptor().getName().toString() ), + new AttributePath(), + null, + null, + null + ); + + this.idClassType = idClassSource.getTypeDescriptor(); + + // todo : as we build these, we need a way to apply: + // 1) column naming overrides (virtualIdentifierComposite) + // 2) MapsId + + // one option is a Builder like I did for annotation sources... + + + for ( AttributeSource attributeSource : idClassSource.attributeSources() ) { + final String attributeName = attributeSource.getName(); + + final SingularAttributeBinding correspondingAttribute = + (SingularAttributeBinding) virtualIdentifierComposite.locateAttributeBinding( attributeName ); + if ( correspondingAttribute == null ) { + throw localBindingContext().makeMappingException( + "Could not locate Entity attribute corresponding to IdClass attribute : " + + idClassType.getName().toString() + '.' + attributeName + ); + } + + SingularAttribute idClassSubAttribute = composite.locateSingularAttribute( attributeName ); + if ( idClassSubAttribute == null ) { + idClassSubAttribute = composite.createSingularAttribute( attributeName ); + } + final SingularAttributeBinding idClassAttributeBinding = new BasicAttributeBinding( + this, + idClassSubAttribute, + correspondingAttribute.getRelationalValueBindings(), + correspondingAttribute.getPropertyAccessorName(), + false, + false, + NaturalIdMutability.NOT_NATURAL_ID, + null, + getRoleBase().append( attributeName ), + getPathBase().append( attributeName ), + PropertyGeneration.NEVER + ); + + if ( BasicAttributeBinding.class.isInstance( correspondingAttribute ) + || EmbeddedAttributeBinding.class.isInstance( correspondingAttribute ) ) { + idClassAttributeBinding.getHibernateTypeDescriptor().copyFrom( + correspondingAttribute.getHibernateTypeDescriptor() + ); + } + else { + idClassAttributeBinding.getHibernateTypeDescriptor().copyFrom( + ( (SingularAssociationAttributeBinding) correspondingAttribute ) + .getReferencedAttributeBinding() + .getHibernateTypeDescriptor() + ); + } + + attributeBindingMap.put( attributeName, idClassAttributeBinding ); + } + + modifiable = false; + } + + @Override + protected boolean isModifiable() { + return modifiable; + } + + @Override + protected Map attributeBindingMapInternal() { + return attributeBindingMap; + } + + @Override + public boolean isAggregated() { + return false; + } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return idClassType; + } + } + + + @Override + public boolean applyToRootEntity() { + return false; + } + + @Override + public void visit(final EntitySource source, BinderLocalBindingContext context) { + final EntityBinding binding = context.locateBinding( source ); + + AbstractNoFollowOnProcess process = new AbstractNoFollowOnProcess() { + @Override + public boolean doProcess() { + bindSubEntityPrimaryKey( binding, source ); + bindSecondaryTables( binding, source ); + markSuperEntityTableAbstractIfNecessary( binding.getSuperEntityBinding() ); + return false; + } + }; + + if ( pendingIdentifierBinder == null ) { + process.doProcess(); + } + else { + pendingIdentifierBinder.addFollowOnProcess( process ); + } + } + + @Override + public void afterAllEntitiesInHierarchy() { + if ( pendingIdentifierBinder == null ) { + rootBindingContext.getEventBus().fireIdentifierResolved( binding ); + } + else { + pendingIdentifierBinder.addFollowOnProcess( + new AbstractNoFollowOnProcess() { + @Override + public boolean doProcess() { + localBindingContext().getEventBus().fireIdentifierResolved( binding ); + return false; + } + } + ); + } + } + + private void bindSubEntityPrimaryKey(EntityBinding entityBinding, EntitySource entitySource) { + final InheritanceType inheritanceType = entityBinding.getHierarchyDetails().getInheritanceType(); + final EntityBinding superEntityBinding = entityBinding.getSuperEntityBinding(); + if ( superEntityBinding == null ) { + throw new AssertionFailure( "super entitybinding is null " ); + } + if ( inheritanceType == InheritanceType.JOINED ) { + final JoinedSubclassEntitySource subclassEntitySource = (JoinedSubclassEntitySource) entitySource; + final List columnSources = subclassEntitySource.getPrimaryKeyColumnSources(); + final TableSpecification table = entityBinding.getPrimaryTable(); + final List joinRelationalValueBindings = + getJoinedPrimaryKeyRelationalValueBindings( superEntityBinding, columnSources, table ); + + entityBinding.setKeyRelationalValueBindings( joinRelationalValueBindings ); + + final List targetColumns = foreignKeyHelper().determineForeignKeyTargetColumns( + superEntityBinding, + subclassEntitySource + ); + + ForeignKey foreignKey = locateOrCreateForeignKey( + subclassEntitySource.getExplicitForeignKeyName(), + table, + joinRelationalValueBindings, + // shouldn't the table here always be the root entity's primary table? + foreignKeyHelper().determineForeignKeyTargetTable( + superEntityBinding, + subclassEntitySource + ), + targetColumns, + subclassEntitySource.isCascadeDeleteEnabled(), + subclassEntitySource.createForeignKeyConstraint() + ); + + if ( subclassEntitySource.isCascadeDeleteEnabled() ) { + entityBinding.setCascadeDeleteEnabled( true ); + } + } + } + + private void bindSecondaryTables(EntityBinding entityBinding, EntitySource entitySource) { + for ( final SecondaryTableSource secondaryTableSource : entitySource.getSecondaryTables() ) { + final TableSpecification table = tableHelper().createTable( + secondaryTableSource.getTableSource(), + new TableNamingStrategyHelper( entityBinding ) + ); + table.addComment( secondaryTableSource.getComment() ); + final List joinRelationalValueBindings = getJoinedPrimaryKeyRelationalValueBindings( + entityBinding, + secondaryTableSource.getPrimaryKeyColumnSources(), + table + ); + + // TODO: make the foreign key column the primary key??? + final List targetColumns = foreignKeyHelper() + .determineForeignKeyTargetColumns( entityBinding, secondaryTableSource ); + final ForeignKey foreignKey = locateOrCreateForeignKey( + secondaryTableSource.getExplicitForeignKeyName(), + table, + joinRelationalValueBindings, + foreignKeyHelper().determineForeignKeyTargetTable( entityBinding, secondaryTableSource ), + targetColumns, + secondaryTableSource.isCascadeDeleteEnabled(), + secondaryTableSource.createForeignKeyConstraint() + ); + SecondaryTable secondaryTable = new SecondaryTable( table, foreignKey ); + if ( secondaryTableSource.getFetchStyle()!=null ) { + secondaryTable.setFetchStyle( secondaryTableSource.getFetchStyle() ); + } + secondaryTable.setInverse( secondaryTableSource.isInverse() ); + secondaryTable.setOptional( secondaryTableSource.isOptional() ); + secondaryTable.setCascadeDeleteEnabled( secondaryTableSource.isCascadeDeleteEnabled() ); + secondaryTable.setCustomDelete( secondaryTableSource.getCustomSqlDelete() ); + secondaryTable.setCustomInsert( secondaryTableSource.getCustomSqlInsert() ); + secondaryTable.setCustomUpdate( secondaryTableSource.getCustomSqlUpdate() ); + entityBinding.addSecondaryTable( secondaryTable ); + rootBindingContext.getMetadataCollector().addSecondaryTable( secondaryTable ); + } + } + + private void markSuperEntityTableAbstractIfNecessary(EntityBinding superEntityBinding) { + if ( superEntityBinding == null ) { + return; + } + if ( superEntityBinding.getHierarchyDetails().getInheritanceType() != InheritanceType.TABLE_PER_CLASS ) { + return; + } + if ( superEntityBinding.isAbstract() != Boolean.TRUE ) { + return; + } + if ( !Table.class.isInstance( superEntityBinding.getPrimaryTable() ) ) { + return; + } + Table.class.cast( superEntityBinding.getPrimaryTable() ).setPhysicalTable( false ); + } + } + + + + + + + + + public static interface AttributeBindingBuilder { + public AttributeBinding buildAttributeBinding( + AttributeBindingContainer container, + AttributeSource attributeSource, + BinderRootContext context); + + public SingularAttributeBinding buildSingularAttributeBinding( + AttributeBindingContainer container, + SingularAttributeSource attributeSource, + BinderRootContext context); + + public PluralAttributeBinding buildPluralAttributeBinding( + AttributeBindingContainer container, + PluralAttributeSource attributeSource, + BinderRootContext context); + + + public BasicAttributeBinding buildBasicAttributeBinding( + AttributeBindingContainer container, + SingularAttributeSource attributeSource, + BinderRootContext context); + + public EmbeddedAttributeBinding buildCompositeAttributeBinding( + AttributeBindingContainer container, + EmbeddedAttributeSource attributeSource, + BinderRootContext context); + + public OneToOneAttributeBinding buildOneToOneAttributeBinding( + AttributeBindingContainer container, + ToOneAttributeSource attributeSource, + BinderRootContext context); + + public ManyToOneAttributeBinding buildManyToOneAttributeBinding( + AttributeBindingContainer container, + ToOneAttributeSource attributeSource, + BinderRootContext context); + + public SingularAttributeBinding buildAnyAttributeBinding( + AttributeBindingContainer container, + SingularAttributeSource attributeSource, + BinderRootContext context); + + public PluralAttributeBinding buildManyToAnyAttributeBinding( + AttributeBindingContainer container, + PluralAttributeSource attributeSource, + BinderRootContext context); + } + +// public static class StandardAttributeBindingBuilder implements AttributeBindingBuilder { +// /** +// * Singleton access +// */ +// public static final StandardAttributeBindingBuilder INSTANCE = new StandardAttributeBindingBuilder(); +// +// private StandardAssociationRelationalBindingResolverImpl standardAssociationRelationalBindingResolver; +// private MappedByAssociationRelationalBindingResolverImpl mappedByAssociationRelationalBindingResolver; +// +// @Override +// public AttributeBinding buildAttributeBinding( +// AttributeBindingContainer container, +// AttributeSource attributeSource, +// BinderRootContext context) { +// if ( attributeSource.isSingular() ) { +// return buildSingularAttributeBinding( +// container, +// (SingularAttributeSource) attributeSource, +// context +// ); +// } +// else { +// return buildPluralAttributeBinding( +// container, +// (PluralAttributeSource) attributeSource, +// context +// ); +// } +// } +// +// @Override +// public SingularAttributeBinding buildSingularAttributeBinding( +// AttributeBindingContainer container, +// SingularAttributeSource attributeSource, +// BinderRootContext context) { +// switch ( attributeSource.getSingularAttributeNature() ) { +// case BASIC: { +// return buildBasicAttributeBinding( +// container, +// attributeSource, +// context +// ); +// } +// case COMPOSITE: { +// return buildCompositeAttributeBinding( +// container, +// (EmbeddedAttributeSource) attributeSource, +// context +// ); +// } +// case MANY_TO_ONE: { +// return buildManyToOneAttributeBinding( +// container, +// (ToOneAttributeSource) attributeSource, +// context +// ); +// } +// case ONE_TO_ONE: { +// return buildOneToOneAttributeBinding( +// container, +// (ToOneAttributeSource) attributeSource, +// context +// ); +// } +// case ANY: { +// return buildAnyAttributeBinding( +// container, +// attributeSource, +// context +// ); +// } +// default: { +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( +// "Unrecognized SingularAttributeNature : " + +// attributeSource.getSingularAttributeNature() +// ); +// } +// } +// } +// +// @Override +// public BasicAttributeBinding buildBasicAttributeBinding( +// AttributeBindingContainer container, +// SingularAttributeSource attributeSource, +// BinderRootContext context) { +// SingularAttribute attribute = container.getAttributeContainer() +// .locateSingularAttribute( attributeSource.getName() ); +// if ( attribute == null ) { +// attribute = createSingularAttribute( container, attributeSource ); +// } +// +// final List relationalValueBindings = determineRelationalValueBindings( +// container, +// attributeSource, +// attribute, +// locateDefaultTableSpecificationForAttribute( container, attributeSource ), +// context +// ); +// final BasicAttributeBinding attributeBinding = container.makeBasicAttributeBinding( +// attribute, +// relationalValueBindings, +// determineAccessStrategyName( attributeSource, context ), +// attributeSource.isIncludedInOptimisticLocking(), +// attributeSource.isLazy(), +// attributeSource.getNaturalIdMutability(), +// createMetaAttributeContext( container, attributeSource ), +// attributeSource.getAttributeRole(), +// attributeSource.getAttributePath(), +// attributeSource.getGeneration() +// ); +// context.typeHelper().bindSingularAttributeType( attributeSource, attributeBinding ); +// return attributeBinding; +// } +// +// protected List determineRelationalValueBindings( +// AttributeBindingContainer container, +// SingularAttributeSource attributeSource, +// SingularAttribute attribute, +// TableSpecification implicitTable, +// BinderRootContext context) { +// return context.relationalValueBindingHelper().createRelationalValueBindings( +// container, +// attributeSource, +// attribute, +// implicitTable, +// false +// ); +// } +// +// protected String determineAccessStrategyName(AttributeSource attributeSource, BinderRootContext context) { +// final String explicitStrategyName = attributeSource.getPropertyAccessorName(); +// if ( explicitStrategyName != null ) { +// return explicitStrategyName; +// } +// +// return context.getMappingDefaults().getPropertyAccessorName(); +// } +// +// @Override +// public EmbeddedAttributeBinding buildCompositeAttributeBinding( +// AttributeBindingContainer container, +// EmbeddedAttributeSource attributeSource, +// BinderRootContext context) { +// final SingularAttribute attribute = locateOrCreateCompositeAttribute( +// container, +// attributeSource, +// context +// ); +// +// if ( attribute == null ) { +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( +// "Could not locate/build composite attribute '" + attributeSource.getName() +// ); +// } +// +// if ( !Aggregate.class.isInstance( attribute.getSingularAttributeType() ) ) { +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( +// "Found existing attribute on container for '" + attributeSource.getName() +// + "', but was expecting an Aggregate" +// ); +// } +// +// EmbeddedAttributeBinding attributeBinding = createAggregatedCompositeAttribute( +// container, +// attributeSource, +// attribute, +// context +// ); +// +// bindAttributes( attributeBinding.getEmbeddableBinding(), attributeSource.getEmbeddableSource() ); +// +// context.typeHelper().bindAggregatedCompositeAttributeType( +// context.getServiceRegistry(), +// isBuildingIdentifierAttributes(), +// (Aggregate) attributeBinding.getAttribute().getSingularAttributeType(), +// // TODO: don't have the default value at this point; shouldn't be needed... +// null, +// attributeBinding +// ); +// return attributeBinding; +// } +// +// protected SingularAttribute locateOrCreateCompositeAttribute( +// AttributeBindingContainer attributeBindingContainer, +// EmbeddedAttributeSource attributeSource, +// BinderRootContext context) { +// SingularAttribute attribute = attributeBindingContainer.getAttributeContainer() +// .locateCompositeAttribute( attributeSource.getName() ); +// +// if ( attribute != null ) { +// return attribute; +// } +// +// final JavaTypeDescriptor compositeTypeDescriptor; +// if ( attributeSource.getEmbeddableSource().getTypeDescriptor() != null ) { +// compositeTypeDescriptor = attributeSource.getEmbeddableSource().getTypeDescriptor(); +// } +// else { +// final EntityMode entityMode = +// attributeBindingContainer.seekEntityBinding().getHierarchyDetails().getEntityMode(); +// compositeTypeDescriptor = context.typeHelper().determineJavaType( +// attributeSource, +// attributeBindingContainer.getAttributeContainer(), +// entityMode +// ); +// } +// +// final Aggregate composite = new Aggregate( compositeTypeDescriptor, null ); +// return attributeBindingContainer.getAttributeContainer().createCompositeAttribute( +// attributeSource.getName(), +// composite +// ); +// } +// +// protected EmbeddedAttributeBinding createAggregatedCompositeAttribute( +// AttributeBindingContainer attributeBindingContainer, +// EmbeddedAttributeSource attributeSource, +// SingularAttribute attribute, +// BinderRootContext context) { +// final Aggregate composite = (Aggregate) attribute.getSingularAttributeType(); +// +// final boolean hasParentReference = StringHelper.isNotEmpty( +// attributeSource.getEmbeddableSource().getParentReferenceAttributeName() +// ); +// +// final SingularAttribute referencingAttribute = hasParentReference +// ? null +// : composite.createSingularAttribute( attributeSource.getEmbeddableSource().getParentReferenceAttributeName() ); +// final NaturalIdMutability naturalIdMutability = attributeSource.getNaturalIdMutability(); +// +// Class tuplizerClass = null; +// if ( attributeSource.getEmbeddableSource().getExplicitTuplizerClassName() != null ) { +// tuplizerClass = context.getServiceRegistry() +// .getService( ClassLoaderService.class ) +// .classForName( attributeSource.getEmbeddableSource().getExplicitTuplizerClassName() ); +// } +// +// return attributeBindingContainer.makeAggregatedCompositeAttributeBinding( +// attribute, +// referencingAttribute, +// tuplizerClass, +// determineAccessStrategyName( attributeSource, context ), +// attributeSource.isIncludedInOptimisticLocking(), +// attributeSource.isLazy(), +// naturalIdMutability, +// createMetaAttributeContext( attributeBindingContainer, attributeSource ), +// attributeSource.getAttributeRole(), +// attributeSource.getAttributePath() +// ); +// } +// +// protected boolean isBuildingIdentifierAttributes() { +// return false; +// } +// +// @Override +// public OneToOneAttributeBinding buildOneToOneAttributeBinding( +// AttributeBindingContainer container, +// ToOneAttributeSource attributeSource, +// BinderRootContext context) { +// SingularAttribute attribute = container.getAttributeContainer() +// .locateSingularAttribute( attributeSource.getName() ); +// if ( attribute == null ) { +// attribute = createSingularAttribute( container, attributeSource ); +// } +// +// final JavaTypeDescriptor referencedEntityJavaClassReference = context.typeHelper().determineJavaType( +// attributeSource, +// container.getAttributeContainer() +// ); +// final EntityBinding referencedEntityBinding = locateEntityBinding( +// referencedEntityJavaClassReference, +// attributeSource.getReferencedEntityName(), +// context +// ); +// +// final AssociationRelationalBindingResolver resolver = +// getAssociationRelationalBindingResolver( attributeSource, context ); +// +// //now find the referenced attribute binding, either the referenced entity's id attribute or the referenced attribute +// //todo referenced entityBinding null check? +// final SingularAttributeBinding referencedAttributeBinding = resolver.resolveOneToOneReferencedAttributeBinding( +// attributeSource, +// referencedEntityBinding +// ); +// // todo : currently a chicken-egg problem here between creating the attribute binding and binding its FK values... +// // now we have everything to create the attribute binding +// final OneToOneAttributeBinding attributeBinding = container.makeOneToOneAttributeBinding( +// attribute, +// determineAccessStrategyName( attributeSource, context ), +// attributeSource.isIncludedInOptimisticLocking(), +// attributeSource.isLazy(), +// attributeSource.getNaturalIdMutability(), +// createMetaAttributeContext( container, attributeSource ), +// attributeSource.getAttributeRole(), +// attributeSource.getAttributePath(), +// referencedEntityBinding, +// referencedAttributeBinding, +// attributeSource.getForeignKeyDirection() == ForeignKeyDirection.FROM_PARENT +// ); +// +// /** +// * this is not correct, here, if no @JoinColumn defined, we simply create the FK column only with column calucated +// * but what we should do is get all the column info from the referenced column(s), including nullable, size etc. +// */ +// final List relationalValueBindings = resolver.resolveOneToOneRelationalValueBindings( +// attributeSource, +// container, +// referencedAttributeBinding +// ); +// final ForeignKey foreignKey; +// if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.FROM_PARENT ) { +// foreignKey = resolver.resolveOneToOneForeignKey( +// attributeSource, +// attributeBinding.getContainer().getPrimaryTable(), +// attributeBinding.getContainer().getPrimaryTable().getPrimaryKey().getColumns(), +// referencedEntityBinding +// ); +// } +// else { +// foreignKey = null; +// } +// attributeBinding.setJoinRelationalValueBindings( relationalValueBindings, foreignKey ); +// +// // Type resolution... +// if ( !attribute.isTypeResolved() ) { +// attribute.resolveType( referencedEntityBinding.getEntity() ); +// } +// +// +// String uniqueKeyAttributeName = null; +// final EntityIdentifier idInfo = referencedEntityBinding.getHierarchyDetails().getEntityIdentifier(); +// if ( idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { +// final EntityIdentifier.AttributeBasedIdentifierBinding idBinding = +// (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); +// final SingularAttributeBinding idAttrBinding = idBinding.getAttributeBinding(); +// if ( referencedAttributeBinding != idAttrBinding ) { +// referencedAttributeBinding.setAlternateUniqueKey( true ); +// uniqueKeyAttributeName = referencedAttributeBinding.getAttributePath().getFullPath(); +// } +// } +// +// final Type resolvedType; +// if ( attributeSource.isMappedBy() || attributeSource.relationalValueSources().isEmpty() ) { +// resolvedType = context.getMetadataCollector().getTypeResolver().getTypeFactory().oneToOne( +// referencedEntityBinding.getEntityName(), +// attributeSource.getForeignKeyDirection(), +// uniqueKeyAttributeName == null, +// uniqueKeyAttributeName, +// attributeSource.getFetchTiming() != FetchTiming.IMMEDIATE, +// attributeSource.isUnWrapProxy(), +// container.seekEntityBinding().getEntityName(), +// attribute.getName() +// ); +// } +// else { +// resolvedType = context.getMetadataCollector().getTypeResolver().getTypeFactory().specialOneToOne( +// referencedEntityBinding.getEntityName(), +// attributeSource.getForeignKeyDirection(), +// uniqueKeyAttributeName == null, +// uniqueKeyAttributeName, +// attributeSource.getFetchTiming() != FetchTiming.IMMEDIATE, +// attributeSource.isUnWrapProxy(), +// container.seekEntityBinding().getEntityName(), +// attribute.getName() +// ); +// } +// +// context.typeHelper().bindHibernateTypeDescriptor( +// attributeBinding.getHibernateTypeDescriptor(), +// attributeSource.getTypeInformation(), +// referencedEntityJavaClassReference, +// resolvedType +// ); +// if ( !attributeBinding.getRelationalValueBindings().isEmpty() ) { +// context.typeHelper().bindJdbcDataType( +// attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(), +// attributeBinding.getRelationalValueBindings() +// ); +// } +// +// bindToOneDetails( attributeSource, attributeBinding ); +// +// return attributeBinding; +// } +// +// protected EntityBinding locateEntityBinding( +// JavaTypeDescriptor referencedEntityTypeDescriptor, +// String explicitEntityName, +// BinderRootContext context) { +// if ( explicitEntityName != null ) { +// return locateEntityBinding( explicitEntityName, context ); +// } +// else if ( referencedEntityTypeDescriptor != null ) { +// return locateEntityBinding( referencedEntityTypeDescriptor.getName().toString(), context ); +// } +// +// throw new IllegalArgumentException( "explicitEntityName and entityJavaClassReference cannot both be null." ); +// } +// +// protected EntityBinding locateEntityBinding(String entityName, BinderRootContext context) { +// // Check if binding has already been created +// EntityBinding entityBinding = context.getMetadataCollector().getEntityBinding( entityName ); +// if ( entityBinding == null ) { +// throw context.getLocalBindingContextSelector() +// .getCurrentBinderLocalBindingContext() +// .makeMappingException( "No entity binding with name: " + entityName ); +// } +// return entityBinding; +// } +// +// protected AssociationRelationalBindingResolver getAssociationRelationalBindingResolver( +// ToOneAttributeSource attributeSource, +// BinderRootContext context) { +// return attributeSource.isMappedBy() +// ? mappedByAssociationRelationalBindingResolver( context ) +// : standardAssociationRelationalBindingResolver( context ); +// } +// +// private AssociationRelationalBindingResolver mappedByAssociationRelationalBindingResolver(BinderRootContext context) { +// if ( mappedByAssociationRelationalBindingResolver == null ) { +// mappedByAssociationRelationalBindingResolver = +// new MappedByAssociationRelationalBindingResolverImpl( context ); +// } +// return mappedByAssociationRelationalBindingResolver; +// } +// +// private AssociationRelationalBindingResolver standardAssociationRelationalBindingResolver(BinderRootContext context) { +// if ( standardAssociationRelationalBindingResolver == null ) { +// standardAssociationRelationalBindingResolver = +// new StandardAssociationRelationalBindingResolverImpl( context ); +// } +// return standardAssociationRelationalBindingResolver; +// } +// +// protected void bindToOneDetails( +// final ToOneAttributeSource attributeSource, +// final SingularAssociationAttributeBinding attributeBinding) { +// attributeBinding.setCascadeStyle( determineCascadeStyle( attributeSource.getCascadeStyles() ) ); +// attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); +// attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); +// } +// +// @Override +// public ManyToOneAttributeBinding buildManyToOneAttributeBinding( +// AttributeBindingContainer container, +// ToOneAttributeSource attributeSource, +// BinderRootContext context) { +// return null; +// } +// +// @Override +// public SingularAttributeBinding buildAnyAttributeBinding( +// AttributeBindingContainer container, +// SingularAttributeSource attributeSource, +// BinderRootContext context) { +// throw new NotYetImplementedException( "Binding ANY mappings not yet implemented" ); +// } +// +// @Override +// public PluralAttributeBinding buildPluralAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// return null; +// } +// +// @Override +// public PluralAttributeBinding buildManyToAnyAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// return null; +// } +// } +// +// public static class PluralAttributesDisallowedAttributeBuilder extends StandardAttributeBindingBuilder { +// /** +// * Singleton access +// */ +// public static final PluralAttributesDisallowedAttributeBuilder INSTANCE = new PluralAttributesDisallowedAttributeBuilder(); +// +// @Override +// public PluralAttributeBinding buildPluralAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// // sources should already disallow this, this is simply a +// // last-stand, fail-safe check so we use a generic exception message +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( "Plural attributes not allowed in this context" ); +// } +// +// @Override +// public PluralAttributeBinding buildManyToAnyAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// // sources should already disallow this, this is simply a +// // last-stand, fail-safe check so we use a generic exception message +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( "Plural attributes not allowed in this context" ); +// } +// +// } +// +// public static class IdentifierAttributeBuilder extends StandardAttributeBindingBuilder { +// /** +// * Singleton access +// */ +// public static final IdentifierAttributeBuilder INSTANCE = new IdentifierAttributeBuilder(); +// +// @Override +// public PluralAttributeBinding buildPluralAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// // sources should already disallow this, this is simply a +// // last-stand, fail-safe check so we use a generic exception message +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( "Plural attributes not allowed in identifier" ); +// } +// +// @Override +// public PluralAttributeBinding buildManyToAnyAttributeBinding( +// AttributeBindingContainer container, +// PluralAttributeSource attributeSource, +// BinderRootContext context) { +// // sources should already disallow this, this is simply a +// // last-stand, fail-safe check so we use a generic exception message +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( "Plural attributes not allowed in identifier" ); +// } +// +// @Override +// public SingularAttributeBinding buildAnyAttributeBinding( +// AttributeBindingContainer container, +// SingularAttributeSource attributeSource, +// BinderRootContext context) { +// // sources should already disallow this, this is simply a +// // last-stand, fail-safe check so we use a generic exception message +// throw context.getLocalBindingContextSelector().getCurrentBinderLocalBindingContext() +// .makeMappingException( "Any mapping not allowed in identifier" ); +// } +// } + + + + + + + + + + + + + + + + + + + + + + + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderEventBus.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderEventBus.java new file mode 100644 index 0000000000..99bc7321d5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderEventBus.java @@ -0,0 +1,163 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.internal.binder; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.hibernate.metamodel.spi.binding.EmbeddableBinding; +import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor; +import org.hibernate.metamodel.spi.binding.HierarchyDetails; + +import org.jboss.logging.Logger; + +/** + * Acts as the central message hub for 2 types of events in the Binder ecosystem:
    + *
  • when an identifier is fully resolved
  • + *
  • when an attribute is fully resolved
  • + *
+ * + * @author Steve Ebersole + */ +public class BinderEventBus implements HibernateTypeDescriptor.ResolutionListener { + private static final Logger log = Logger.getLogger( BinderEventBus.class ); + + private List identifierBindingListeners; + private List attributeBindingListeners; + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // IdentifierBindingListener + + public void addIdentifierBindingListener(IdentifierBindingListener listener) { + log.debugf( "Adding IdentifierBindingListener : %s ", listener ); + + if ( identifierBindingListeners == null ) { + identifierBindingListeners = new ArrayList(); + } + identifierBindingListeners.add( listener ); + } + + public void removeIdentifierBindingListener(IdentifierBindingListener listener) { + log.debugf( "Removing IdentifierBindingListener : %s ", listener ); + + if ( identifierBindingListeners == null ) { + throw new IllegalStateException( "No listeners defined" ); + } + + identifierBindingListeners.remove( listener ); + } + + private int identifierResolutionDepth = 0; + + private List completedIdentifierBindingListeners; + + public void fireIdentifierResolved(HierarchyDetails hierarchyDetails) { + final String entityName = hierarchyDetails.getRootEntityBinding().getEntityName(); + log.debugf( "Starting 'identifier resolved' notifications : %s ", entityName ); + + if ( identifierBindingListeners == null ) { + return; + } + + identifierResolutionDepth++; + try { + for ( IdentifierBindingListener identifierBindingListener : identifierBindingListeners ) { + log.tracef( + " - sending 'identifier resolved' notification [%s] to IdentifierBindingListener : %s", + entityName, + identifierBindingListener + ); + final boolean done = identifierBindingListener.identifierResolved( hierarchyDetails ); + if ( done ) { + if ( completedIdentifierBindingListeners == null ) { + completedIdentifierBindingListeners = new ArrayList(); + } + completedIdentifierBindingListeners.add( identifierBindingListener ); + } + } + } + finally { + identifierResolutionDepth--; + } + + if ( identifierResolutionDepth == 0 ) { + if ( completedIdentifierBindingListeners != null + && !completedIdentifierBindingListeners.isEmpty() ) { + identifierBindingListeners.removeAll( completedIdentifierBindingListeners ); + } + } + } + + public void finishUpIdentifiers() { + // todo : how to best allow all listeners to report any un-resolved state and still throw an excetpion here? + + // for now, we throw an error if there are any remaining listeners + if ( identifierBindingListeners != null && !identifierBindingListeners.isEmpty() ) { + throw new IllegalStateException( "Could not resolve all identifiers" ); + } + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // AttributeBindingListener + + public void addAttributeBindingListener(AttributeBindingListener listener) { + log.debugf( "Adding AttributeBindingListener : %s ", listener ); + + if ( attributeBindingListeners == null ) { + attributeBindingListeners = new ArrayList(); + } + attributeBindingListeners.add( listener ); + } + + public void removeAttributeBindingListener(AttributeBindingListener listener) { + log.debugf( "Removing AttributeBindingListener : %s ", listener ); + + if ( attributeBindingListeners == null ) { + throw new IllegalStateException( "No listeners defined" ); + } + + attributeBindingListeners.remove( listener ); + } + + public void finishUpAttributes() { + // todo : how to best allow all listeners to report any un-resolved state and still throw an excetpion here? + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // HibernateTypeDescriptor.ResolutionListener + + @Override + public void typeResolved(HibernateTypeDescriptor typeDescriptor) { + + } + + + public void fireEmbeddableResolved(EmbeddableBinding binding) { + + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderLocalBindingContextSelectorImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderLocalBindingContextSelectorImpl.java index 9b129a5366..5ff533a003 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderLocalBindingContextSelectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderLocalBindingContextSelectorImpl.java @@ -94,6 +94,16 @@ public class BinderLocalBindingContextSelectorImpl implements BinderLocalBinding return parent().getLocalBindingContextSelector(); } + @Override + public BinderEventBus getEventBus() { + return parent().getEventBus(); + } + + @Override + public SourceIndex getSourceIndex() { + return parent().getSourceIndex(); + } + @Override public HibernateTypeHelper typeHelper() { return parent().typeHelper(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderProcessHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderProcessHelper.java index b3b9a1b0fe..f2041a4b54 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderProcessHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderProcessHelper.java @@ -39,45 +39,52 @@ import org.hibernate.metamodel.spi.binding.InheritanceType; * EntitySource structure skipping MapperSuperclassSource types. * * @author Steve Ebersole + * @author Gail Badner */ public class BinderProcessHelper { private final BinderRootContext context; - public static final BinderStepHierarchyStrategy NOOP_HIERARCHY_STRATEGY = new BinderStepHierarchyStrategy() { - @Override - public void visit(EntityHierarchySource source, BinderLocalBindingContext context) { - - } - }; - - public static final BinderStepEntityStrategy NOOP_ENTITY_STRATEGY = new BinderStepEntityStrategy() { - @Override - public boolean applyToRootEntity() { - return false; - } - - @Override - public void visit(EntitySource source, BinderLocalBindingContext context) { - - } - }; - public BinderProcessHelper(BinderRootContext context) { this.context = context; } + /** + * Public method to apply the "hierarchy strategy" to each hierarchy source + * object. + * + * @param hierarchySources The hierarchy sources + * @param hierarchyStrategy The strategy to call back into + */ public void apply( Collection hierarchySources, BinderStepHierarchyStrategy hierarchyStrategy) { for ( EntityHierarchySource hierarchySource : hierarchySources ) { - apply( hierarchySource, hierarchyStrategy ); + apply( hierarchySource, hierarchyStrategy, NOOP_ENTITY_STRATEGY ); } } - public void apply(EntityHierarchySource hierarchySource, BinderStepHierarchyStrategy hierarchyStrategy) { - apply( hierarchySource, hierarchyStrategy, NOOP_ENTITY_STRATEGY ); + /** + * Public method to apply the "entity strategy" to each hierarchy source + * object. + * + * @param hierarchySources The hierarchy sources + * @param entityStrategy The strategy to call back into + */ + public void apply( + Collection hierarchySources, + BinderStepEntityStrategy entityStrategy) { + for ( EntityHierarchySource hierarchySource: hierarchySources ) { + apply( hierarchySource, NOOP_HIERARCHY_STRATEGY, entityStrategy ); + } } + /** + * Public method to apply the "combined strategy" to each hierarchy source + * object. + * + * @param hierarchySources The hierarchy sources + * @param strategy The strategy to call back into + */ public void apply( Collection hierarchySources, BinderStepCombinedStrategy strategy) { @@ -86,22 +93,26 @@ public class BinderProcessHelper { } } + + /** + * Public method to apply the "combined strategy" to a single hierarchy source + * object. + * + * @param hierarchySource The hierarchy source + * @param strategy The strategy to call back into + */ public void apply(EntityHierarchySource hierarchySource, BinderStepCombinedStrategy strategy) { apply( hierarchySource, strategy, strategy ); } - public void apply( - Collection hierarchySources, - BinderStepEntityStrategy entityStrategy) { - for ( EntityHierarchySource hierarchySource: hierarchySources ) { - apply( hierarchySource, entityStrategy ); - } - } - - public void apply(EntityHierarchySource hierarchySource, BinderStepEntityStrategy strategy) { - apply( hierarchySource, NOOP_HIERARCHY_STRATEGY, strategy ); - } - + /** + * Public method to apply the "combined strategy" to each hierarchy source + * object. + * + * @param hierarchySources The hierarchy sources + * @param hierarchyStrategy The hierarchy strategy to call back into + * @param entityStrategy The entity strategy to call back into + */ public void apply( Collection hierarchySources, BinderStepHierarchyStrategy hierarchyStrategy, @@ -129,6 +140,10 @@ public class BinderProcessHelper { if ( hierarchySource.getHierarchyInheritanceType() != InheritanceType.NO_INHERITANCE ) { visitSubclasses( rootEntitySource, entityStrategy, localContext ); } + + entityStrategy.afterAllEntitiesInHierarchy(); + + selector.unsetCurrent(); } private void visitSubclasses( @@ -142,4 +157,32 @@ public class BinderProcessHelper { visitSubclasses( subType, entityStrategy, localContext ); } } + + + /** + * A no-op version of the BinderStepHierarchyStrategy contract + */ + public static final BinderStepHierarchyStrategy NOOP_HIERARCHY_STRATEGY = new BinderStepHierarchyStrategy() { + @Override + public void visit(EntityHierarchySource source, BinderLocalBindingContext context) { + } + }; + + /** + * A no-op version of the BinderStepEntityStrategy contract + */ + public static final BinderStepEntityStrategy NOOP_ENTITY_STRATEGY = new BinderStepEntityStrategy() { + @Override + public boolean applyToRootEntity() { + return false; + } + + @Override + public void visit(EntitySource source, BinderLocalBindingContext context) { + } + + @Override + public void afterAllEntitiesInHierarchy() { + } + }; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContext.java index 338fe0947f..de55b920f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContext.java @@ -55,10 +55,14 @@ public interface BinderRootContext extends BindingContext { public BinderLocalBindingContextSelector getLocalBindingContextSelector(); + public BinderEventBus getEventBus(); + public SourceIndex getSourceIndex(); + HibernateTypeHelper typeHelper(); RelationalIdentifierHelper relationalIdentifierHelper(); TableHelper tableHelper(); ForeignKeyHelper foreignKeyHelper(); RelationalValueBindingHelper relationalValueBindingHelper(); NaturalIdUniqueKeyHelper naturalIdUniqueKeyHelper(); + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContextImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContextImpl.java index 800e37122f..cf89951872 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderRootContextImpl.java @@ -37,6 +37,8 @@ import org.hibernate.metamodel.spi.binding.HierarchyDetails; * @author Steve Ebersole */ public class BinderRootContextImpl extends BaseDelegatingBindingContext implements BinderRootContext { + private final SourceIndex sourceIndex; + private final BinderEventBus eventBus; private Map hierarchySourceToBindingMap = new HashMap(); private Map entitySourceToBindingMap @@ -51,8 +53,10 @@ public class BinderRootContextImpl extends BaseDelegatingBindingContext implemen private final BinderLocalBindingContextSelector localBindingContextSelector; - public BinderRootContextImpl(BindingContext parent) { + public BinderRootContextImpl(BindingContext parent, SourceIndex sourceIndex, BinderEventBus eventBus) { super( parent ); + this.sourceIndex = sourceIndex; + this.eventBus = eventBus; this.typeHelper = new HibernateTypeHelper( this ); this.relationalIdentifierHelper = new RelationalIdentifierHelper( this ); @@ -63,6 +67,15 @@ public class BinderRootContextImpl extends BaseDelegatingBindingContext implemen this.localBindingContextSelector = new BinderLocalBindingContextSelectorImpl( this ); } + public BinderEventBus getEventBus() { + return eventBus; + } + + @Override + public SourceIndex getSourceIndex() { + return sourceIndex; + } + public void addMapping(EntityHierarchySource source, HierarchyDetails binding) { hierarchySourceToBindingMap.put( source, binding ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderStepEntityStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderStepEntityStrategy.java index bb5fad5b66..3d1b148af8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderStepEntityStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/BinderStepEntityStrategy.java @@ -39,4 +39,6 @@ public interface BinderStepEntityStrategy { public boolean applyToRootEntity(); public void visit(EntitySource source, BinderLocalBindingContext context); + + public void afterAllEntitiesInHierarchy(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/ForeignKeyHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/ForeignKeyHelper.java index f8e6930968..2d17f90277 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/ForeignKeyHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/ForeignKeyHelper.java @@ -28,6 +28,7 @@ import java.util.List; import org.hibernate.AssertionFailure; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.internal.binder.ConstraintNamingStrategyHelper.ForeignKeyNamingStrategyHelper; import org.hibernate.metamodel.source.spi.ForeignKeyContributingSource; import org.hibernate.metamodel.spi.binding.AttributeBinding; @@ -99,15 +100,19 @@ public class ForeignKeyHelper { public SingularAttributeBinding determineReferencedAttributeBinding( final ForeignKeyContributingSource foreignKeyContributingSource, final EntityBinding referencedEntityBinding) { + // todo : this is definitely the place that leads to problems with @Id @ManyToOne + final ForeignKeyContributingSource.JoinColumnResolutionDelegate resolutionDelegate = foreignKeyContributingSource.getForeignKeyTargetColumnResolutionDelegate(); - final ForeignKeyContributingSource.JoinColumnResolutionContext resolutionContext = resolutionDelegate == null ? null : new JoinColumnResolutionContextImpl( - referencedEntityBinding - ); if ( resolutionDelegate == null ) { - return referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); + return referencedEntityBinding.getHierarchyDetails().getEntityIdentifier() + .getEntityIdentifierBinding() + .getAttributeBinding(); } + final ForeignKeyContributingSource.JoinColumnResolutionContext resolutionContext = + new JoinColumnResolutionContextImpl( referencedEntityBinding ); + final String explicitName = resolutionDelegate.getReferencedAttributeName(); final AttributeBinding referencedAttributeBinding; if ( explicitName != null ) { @@ -256,33 +261,34 @@ public class ForeignKeyHelper { String logicalTableName, String logicalSchemaName, String logicalCatalogName) { - if ( bindingContext().quoteIdentifiersInContext() && !org.hibernate - .internal - .util - .StringHelper - .isQuoted( logicalColumnName ) ) { - logicalColumnName = org.hibernate.internal.util.StringHelper.quote( logicalColumnName ); + if ( bindingContext().quoteIdentifiersInContext() + && !StringHelper.isQuoted( logicalColumnName ) ) { + logicalColumnName = StringHelper.quote( logicalColumnName ); } - return resolveTable( logicalTableName, logicalSchemaName, logicalCatalogName ).locateOrCreateColumn( - logicalColumnName - ); + return resolveTable( logicalTableName, logicalSchemaName, logicalCatalogName ) + .locateOrCreateColumn( logicalColumnName ); } @Override public TableSpecification resolveTable(String logicalTableName, String logicalSchemaName, String logicalCatalogName) { Identifier tableIdentifier = helperContext.relationalIdentifierHelper().createIdentifier( logicalTableName ); if ( tableIdentifier == null ) { + // todo : why not just return referencedEntityBinding.getPrimaryTable() here? + // is it really valid to expect the table name to be missing, but the + // schema/catalog to be specified as an indication to look for a table + // with the same name as the primary table, but in the specified + // schema/catalog? tableIdentifier = referencedEntityBinding.getPrimaryTable().getLogicalName(); } - - Identifier catalogName = org.hibernate.internal.util.StringHelper.isNotEmpty( logicalCatalogName ) ? - Identifier.toIdentifier( logicalCatalogName ) + final Identifier catalogName = StringHelper.isNotEmpty( logicalCatalogName ) + ? Identifier.toIdentifier( logicalCatalogName ) : referencedEntityBinding.getPrimaryTable().getSchema().getName().getCatalog(); - Identifier schemaName = org.hibernate.internal.util.StringHelper.isNotEmpty( logicalCatalogName ) ? - Identifier.toIdentifier( logicalSchemaName ) + final Identifier schemaName = StringHelper.isNotEmpty( logicalCatalogName ) + ? Identifier.toIdentifier( logicalSchemaName ) : referencedEntityBinding.getPrimaryTable().getSchema().getName().getSchema(); - Schema schema = bindingContext().getMetadataCollector().getDatabase().getSchema( catalogName, schemaName ); + final Schema schema = bindingContext().getMetadataCollector().getDatabase() + .getSchema( catalogName, schemaName ); return schema.locateTable( tableIdentifier ); } @@ -316,7 +322,10 @@ public class ForeignKeyHelper { private SingularAttributeBinding resolveReferencedAttributeBinding(String attributeName) { if ( attributeName == null ) { - return referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); + return referencedEntityBinding.getHierarchyDetails() + .getEntityIdentifier() + .getEntityIdentifierBinding() + .getAttributeBinding(); } final AttributeBinding referencedAttributeBinding = referencedEntityBinding.locateAttributeBindingByPath( attributeName, true ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/HibernateTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/HibernateTypeHelper.java index 4afae81cc6..c77eaab8e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/HibernateTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/HibernateTypeHelper.java @@ -36,6 +36,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.util.beans.BeanInfoHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.reflite.spi.ClassDescriptor; @@ -54,6 +55,7 @@ import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.spi.InFlightMetadataCollector; import org.hibernate.metamodel.spi.PluralAttributeElementNature; import org.hibernate.metamodel.spi.PluralAttributeNature; +import org.hibernate.metamodel.spi.SingularAttributeNature; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; @@ -84,6 +86,8 @@ import org.hibernate.type.TypeFactory; import org.jboss.jandex.DotName; import org.jboss.logging.Logger; +import static org.hibernate.metamodel.spi.binding.EntityIdentifier.IdClassMetadata; + /** * Delegate for handling:
    *
  1. @@ -112,7 +116,7 @@ import org.jboss.logging.Logger; * @author Gail Badner * @author Brett Meyer */ -class HibernateTypeHelper { +public class HibernateTypeHelper { private static final Logger log = Logger.getLogger( HibernateTypeHelper.class ); /** @@ -414,6 +418,33 @@ class HibernateTypeHelper { elementBinding.getRelationalValueBindings() ); } + + + public void bindNonAggregatedCompositeIdentifierType( + ServiceRegistry serviceRegistry, + EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding) { + final CompositeType idType; + + final CompositeType virtualIdType = (CompositeType) idBinding.getHibernateType( serviceRegistry, typeFactory() ); + final IdClassMetadata idClassMetadata = idBinding.getIdClassMetadata(); + if ( idClassMetadata != null ) { + idType = (CompositeType) idClassMetadata.getHibernateType( serviceRegistry, typeFactory() ); + } + else { + idType = virtualIdType; + } + + idBinding.getAttributeBinding().getHibernateTypeDescriptor().setResolvedTypeMapping( idType ); + bindHibernateTypeDescriptor( + idBinding.getAttributeBinding().getHibernateTypeDescriptor(), + idType.getReturnedClass().getName(), + null, + null, + idType + ); + + } + void bindNonAggregatedCompositeIdentifierType( final ServiceRegistry serviceRegistry, final EmbeddedAttributeBinding syntheticAttributeBinding, @@ -433,6 +464,7 @@ class HibernateTypeHelper { resolvedType ); } + void bindManyToManyAttributeType( final PluralAttributeElementBindingManyToMany elementBinding, final PluralAttributeElementSourceManyToMany elementSource, @@ -483,14 +515,17 @@ class HibernateTypeHelper { final JavaTypeDescriptor defaultTypeDescriptor; if ( attributeTypeDescriptor != null ) { attributeBinding.getAttribute().resolveType( - makeDomainType( attributeTypeDescriptor.getName().toString() ) + bindingContext().locateOrBuildDomainType( + attributeTypeDescriptor, + attributeSource.getSingularAttributeNature() == SingularAttributeNature.COMPOSITE + ) ); defaultTypeDescriptor = attributeTypeDescriptor; } else { defaultTypeDescriptor = null; } - //do our best to full fill hibernateTypeDescriptor + //do our best to fully fill hibernateTypeDescriptor bindHibernateTypeDescriptor( hibernateTypeDescriptor, attributeSource.getTypeInformation(), @@ -969,10 +1004,14 @@ class HibernateTypeHelper { */ private static String getReferencedPropertyNameIfNotId( final PluralAttributeBinding pluralAttributeBinding) { - EntityIdentifier entityIdentifier = - pluralAttributeBinding.getContainer().seekEntityBinding().getHierarchyDetails().getEntityIdentifier(); - final String idAttributeName = - entityIdentifier.getAttributeBinding().getAttribute().getName(); + EntityIdentifier entityIdentifier = pluralAttributeBinding.getContainer() + .seekEntityBinding() + .getHierarchyDetails() + .getEntityIdentifier(); + final String idAttributeName = entityIdentifier.getEntityIdentifierBinding() + .getAttributeBinding() + .getAttribute() + .getName(); return pluralAttributeBinding.getReferencedPropertyName().equals( idAttributeName ) ? null : pluralAttributeBinding.getReferencedPropertyName(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/IdentifierBindingListener.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/IdentifierBindingListener.java new file mode 100644 index 0000000000..894c2762be --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/IdentifierBindingListener.java @@ -0,0 +1,40 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.internal.binder; + +import org.hibernate.metamodel.spi.binding.HierarchyDetails; + +/** + * @author Steve Ebersole + */ +public interface IdentifierBindingListener { + /** + * + * @param hierarchyDetails + * + * @return {@code true} indicates that the listener should be removed; {@code false} + * indicates it should stay. + */ + public boolean identifierResolved(HierarchyDetails hierarchyDetails); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/SourceIndex.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/SourceIndex.java index 6b0dd05a35..f42ff872bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/SourceIndex.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/SourceIndex.java @@ -23,15 +23,22 @@ */ package org.hibernate.metamodel.internal.binder; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import org.hibernate.AssertionFailure; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.CoreLogging; import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.AttributeSource; @@ -42,6 +49,7 @@ import org.hibernate.metamodel.source.spi.EntitySource; import org.hibernate.metamodel.source.spi.IdentifiableTypeSource; import org.hibernate.metamodel.source.spi.IdentifierSource; import org.hibernate.metamodel.source.spi.IndexedPluralAttributeSource; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.PluralAttributeIndexSourceResolver; import org.hibernate.metamodel.source.spi.PluralAttributeSource; @@ -49,6 +57,7 @@ import org.hibernate.metamodel.source.spi.SimpleIdentifierSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.ToOneAttributeSource; import org.hibernate.metamodel.spi.AttributeRole; +import org.hibernate.metamodel.spi.BindingContext; import org.hibernate.metamodel.spi.SingularAttributeNature; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; @@ -57,24 +66,325 @@ import org.hibernate.metamodel.spi.relational.Column; import org.jboss.logging.Logger; /** - * Used to build indexes (x-refs) of various parts of an entity hierarchy and - * its attributes. - * + * Builds indexes (cross references) of the various parts of the source model + * for Binder access. + *

    + * The main contracts of SourceIndex are:

      + *
    • + * Indexing the entities in each hierarchy : {@link #indexHierarchy} + *
    • + *
    • + * Accessing all hierarchies:
        + *
      • {@link #getAllHierarchySources()}
      • + *
      • {@link #getIdDependencyOrderedHierarchySources()}
      • + *
      + *
    • + *
    • + * Accessing the attributes in various ways:
        + *
      • {@link #attributeSource(AttributeRole)}
      • + *
      • {@link #attributeSource(EntityBinding, AttributeBinding)}
      • + *
      • {@link #attributeSource(String, String)}
      • + *
      • {@link #getSingularAttributeSources}
      • + *
      • {@link #getPluralAttributeSources}
      • + *
      + *
    • + *
    • + * This notion of "resolving associations" at the source level. See + * {@link #resolveAssociationSources}. I really want to look at this + * and the point it is trying to solve. + *
    • + *
    + * @author Gail Badner * @author Steve Ebersole */ public class SourceIndex { private static final Logger log = CoreLogging.logger( SourceIndex.class ); - private final Map entitySourceIndexByEntityName = new HashMap(); - private final Map attributeSourcesByKey = new HashMap(); + private final BindingContext context; - private final Map mappedByAttributeKeysByOwnerAttributeKeys = - new HashMap(); + private final Map entityHierarchiesByRootEntityName; + private final Map entitySourceIndexByEntityName; + private final Map attributeSourcesByKey; + private final Map mappedByAttributeKeysByOwnerAttributeKeys; + + public SourceIndex(BindingContext context) { + this.context = context; + this.entityHierarchiesByRootEntityName = new LinkedHashMap(); + this.entitySourceIndexByEntityName = new HashMap(); + this.attributeSourcesByKey = new HashMap(); + this.mappedByAttributeKeysByOwnerAttributeKeys = new HashMap(); + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Accessing hierarchies + + /** + * Access to source information about an entity hierarchy by its root entity + * name + * + * @param rootEntityName The root entity name + * + * @return The hierarchy source information. + */ + public EntityHierarchySource getHierarchySourceByRootEntityName(String rootEntityName) { + return entityHierarchiesByRootEntityName.get( rootEntityName ); + } + + /** + * Obtains source information about all entity hierarchies. + *

    + * Note that a Collection is returned because no order is undefined; + * see {@link #getIdDependencyOrderedHierarchySources()} + * + * @return Source information about all entity hierarchies. + */ + public Collection getAllHierarchySources() { + return entityHierarchiesByRootEntityName.values(); + } + + /** + * Used to hold the essential ordering information for a hierarchy + */ + public static class HierarchyByIdDependencyGraphNode { + private final String hierarchyKey; + private final EntityIdentifierNature nature; + private boolean containsUnknownTarget = false; + private final Set targets; + + + public HierarchyByIdDependencyGraphNode(String hierarchyKey, EntityIdentifierNature nature) { + this.hierarchyKey = hierarchyKey; + this.nature = nature; + this.targets = new HashSet(); + } + + public void toggleUnknownTarget() { + // todo : how to best utilize containsUnknownTarget in sorting? + containsUnknownTarget = true; + } + } + + + /** + * Comparator of HierarchyByIdDependencyGraphNode instances used to help + * in ordering the hierarchies. + */ + public static class HierarchyByIdDependencyGraphNodeComparator + implements Comparator { + @Override + public int compare( + HierarchyByIdDependencyGraphNode o1, + HierarchyByIdDependencyGraphNode o2) { + if ( o1.hierarchyKey.equals( o2.hierarchyKey ) ) { + return 0; + } + + final boolean o1HasDeps = !o1.targets.isEmpty(); + final boolean o2HasDeps = !o2.targets.isEmpty(); + + if ( !o1HasDeps ) { + // o1 has no id dependencies, + if ( o2HasDeps ) { + // but o2 does: o1 comes BEFORE o2 + return -1; + } + else { + // neither has id dependencies + return o1.nature == EntityIdentifierNature.SIMPLE + ? -1 + : 1; + } + } + + // to get here, we know the o1 hierarchy has one or more id dependencies + + if ( !o2HasDeps ) { + // but, o2 did not : 01 comes AFTER o2 + return 1; + } + + + if ( o2.targets.contains( o1.hierarchyKey ) ) { + // o2 "depends on" o1 : o1 needs to come BEFORE 02 + return -1; + } + else { + // otherwise : put o1 AFTER o2 + return 1; + } + } + } + + /** + * Obtains source information about all entity hierarchies. Attempts a best + * effort to order the hierarchy according to identifier dependencies. + * + * @return Source information about all entity hierarchies, ordered. + * + * @return The ordered hierarchy source information. + */ + public List getIdDependencyOrderedHierarchySources() { + // it is important that this be called only after all hierarchies have been + // applied and indexed!! Duh :) + // + // Also, this is likely an expensive operation and it is best it be + // called just once (like while processing identifiers). + + final TreeSet nodeSet = + new TreeSet( new HierarchyByIdDependencyGraphNodeComparator() ); + + for ( Map.Entry hierarchySourceEntry : + entityHierarchiesByRootEntityName.entrySet() ) { + final HierarchyByIdDependencyGraphNode node = new HierarchyByIdDependencyGraphNode( + hierarchySourceEntry.getKey(), + hierarchySourceEntry.getValue().getIdentifierSource().getNature() + ); + collectRootEntityNamesOnWhichIdDepends( hierarchySourceEntry.getValue(), node ); + nodeSet.add( node ); + + } + + final List rtn = new ArrayList(); + for ( HierarchyByIdDependencyGraphNode node : nodeSet ) { + rtn.add( entityHierarchiesByRootEntityName.get( node.hierarchyKey ) ); + } + + return rtn; + } + + private void collectRootEntityNamesOnWhichIdDepends( + EntityHierarchySource entityHierarchySource, + HierarchyByIdDependencyGraphNode node) { + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // First, identifier attributes (key-many-to-one) + // + // id attribute(s) can only be basic or to-one types.. assume the source producer + // handle at least that properly + + if ( node.nature == EntityIdentifierNature.SIMPLE ) { + final SimpleIdentifierSource identifierSource = (SimpleIdentifierSource) entityHierarchySource.getIdentifierSource(); + if ( identifierSource.getIdentifierAttributeSource().getSingularAttributeNature() == SingularAttributeNature.BASIC ) { + return; + } + addDependency( node, (ToOneAttributeSource) identifierSource.getIdentifierAttributeSource() ); + } + else if ( node.nature == EntityIdentifierNature.AGGREGATED_COMPOSITE ) { + final AggregatedCompositeIdentifierSource identifierSource = + (AggregatedCompositeIdentifierSource) entityHierarchySource.getIdentifierSource(); + for ( AttributeSource attributeSource : identifierSource.getIdentifierAttributeSource() + .getEmbeddableSource() + .attributeSources() ) { + final SingularAttributeSource sAttSource = (SingularAttributeSource) attributeSource; + if ( sAttSource.getSingularAttributeNature() == SingularAttributeNature.BASIC ) { + continue; + } + addDependency( node, (ToOneAttributeSource) sAttSource ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Then @MapsId + to-one + // + // We make a natural assumption that persistent subclasses cannot (re)define @MapsId... + for ( MapsIdSource mapsIdSource : identifierSource.getMapsIdSources() ) { + final ToOneAttributeSource toOneAttributeSource = mapsIdSource.getAssociationAttributeSource(); + addDependency( node, toOneAttributeSource ); + } + } + else if ( node.nature == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final NonAggregatedCompositeIdentifierSource identifierSource = + (NonAggregatedCompositeIdentifierSource) entityHierarchySource.getIdentifierSource(); + for ( SingularAttributeSource attributeSource : identifierSource.getAttributeSourcesMakingUpIdentifier() ) { + if ( attributeSource.getSingularAttributeNature() == SingularAttributeNature.BASIC ) { + continue; + } + addDependency( node, (ToOneAttributeSource) attributeSource ); + } + } + + } + + private void addDependency( + HierarchyByIdDependencyGraphNode node, + ToOneAttributeSource attributeSource) { + final String entityName = attributeSource.getReferencedEntityName(); + if ( entityName == null ) { + // best effort.. just return + node.toggleUnknownTarget(); + return; + } + + final String rootEntityName = entitySourceIndexByEntityName.get( entityName ) + .entitySource + .getHierarchy() + .getRoot() + .getEntityName(); + + node.targets.add( rootEntityName ); + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Accessing attributes + + public Map getSingularAttributeSources( + String entityName, + boolean isMappedBy, + SingularAttributeNature singularAttributeNature) { + final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName ); + return entitySourceIndex.getSingularAttributeSources( isMappedBy, singularAttributeNature ); + } + + public Map getPluralAttributeSources( + String entityName, + boolean isInverse) { + final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName ); + return entitySourceIndex.getPluralAttributeSources( isInverse ); + } + + public AttributeSource attributeSource(final AttributeRole attributeRole) { + return attributeSourcesByKey.get( attributeRole ); + } + + public AttributeSource attributeSource(String entityName, String attributePath) { + final AttributeRole base = new AttributeRole( entityName ); + + AttributeRole role; + if ( attributePath.contains( "." ) ) { + role = base; + for ( String part : attributePath.split( "\\." ) ) { + role = role.append( part ); + } + } + else { + role = base.append( attributePath ); + } + return attributeSourcesByKey.get( role ); + } + + public AttributeSource attributeSource(EntityBinding entityBinding, AttributeBinding attributeBinding) { + return attributeSourcesByKey.get( attributeBinding.getAttributeRole() ); + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Resolving associations + + public void resolveAssociationSources(EntitySource source, BinderLocalBindingContext context) { + final EntityBinding binding = context.locateBinding( source ); + entitySourceIndexByEntityName.get( binding.getEntityName() ).resolveAttributeSources( context ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Indexing public void indexHierarchy(EntityHierarchySource hierarchy) { final String hierarchyKey = hierarchy.getRoot().getEntityName(); + + entityHierarchiesByRootEntityName.put( hierarchyKey, hierarchy ); + final HierarchyInfo hierarchyInfo = new HierarchyInfo( hierarchyKey, hierarchy ); indexIdentifierAttributeSources( hierarchy, hierarchyInfo ); @@ -92,6 +402,14 @@ public class SourceIndex { } private void indexEntitySource(EntitySource entitySource, HierarchyInfo hierarchyInfo) { + + // todo : consider resolving JavaTypeDescriptor or even o.h.metamodel.spi.domain model as as we index the sources.\ + // + // This is especially useful for associations and components (mainly in HBM + // uses, as in Annotation uses the JavaTypeDescriptor is already known). + // + // See org.hibernate.metamodel.source.spi.JavaTypeDescriptorResolvable + final String entityName = entitySource.getEntityName(); EntitySourceIndex entitySourceIndex = new EntitySourceIndex( this, hierarchyInfo, entitySource ); entitySourceIndexByEntityName.put( entityName, entitySourceIndex ); @@ -139,7 +457,7 @@ public class SourceIndex { attributeSourcesByKey.put( attributeSource.getAttributeRole(), attributeSource ); if ( attributeSource.isSingular() ) { - attributeIndexingTarget.indexSingularAttributeSource( (SingularAttributeSource) attributeSource, isInIdentifier ); + attributeIndexingTarget.indexSingularAttributeSource( (SingularAttributeSource) attributeSource ); } else { attributeIndexingTarget.indexPluralAttributeSource( (PluralAttributeSource) attributeSource ); @@ -163,72 +481,85 @@ public class SourceIndex { } - - - - - - - - - public void resolveAssociationSources(EntitySource source, BinderLocalBindingContext context) { - final EntityBinding binding = context.locateBinding( source ); - entitySourceIndexByEntityName.get( binding.getEntityName() ).resolveAttributeSources( context ); - } - - public Map getSingularAttributeSources( - String entityName, - boolean isMappedBy, - SingularAttributeNature singularAttributeNature) { - final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName ); - return entitySourceIndex.getSingularAttributeSources( isMappedBy, singularAttributeNature ); - } - - public Map getPluralAttributeSources( - String entityName, - boolean isInverse) { - final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName ); - return entitySourceIndex.getPluralAttributeSources( isInverse ); - } - - public AttributeSource attributeSource(final AttributeRole attributeRole) { - return attributeSourcesByKey.get( attributeRole ); - } - - public AttributeSource attributeSource(String entityName, String attributePath) { - final AttributeRole base = new AttributeRole( entityName ); - - AttributeRole role; - if ( attributePath.contains( "." ) ) { - role = base; - for ( String part : attributePath.split( "\\." ) ) { - role = role.append( part ); - } - } - else { - role = base.append( attributePath ); - } - return attributeSourcesByKey.get( role ); - } - - public AttributeSource attributeSource(EntityBinding entityBinding, AttributeBinding attributeBinding) { - return attributeSourcesByKey.get( attributeBinding.getAttributeRole() ); - } - + /** + * Interface to target where attributes should be indexed. Mainly this is + * used to collect id attributes into one pool, and non-id attributes into another. + */ private static interface AttributeIndexingTarget { - public void indexSingularAttributeSource(SingularAttributeSource attributeSource, boolean isInIdentifier); + public void indexSingularAttributeSource(SingularAttributeSource attributeSource); public void indexPluralAttributeSource(PluralAttributeSource attributeSource); } - private static abstract class AbstractAttributeIndexingTarget implements AttributeIndexingTarget { - private final Map unresolvedSingularAttributeSourcesByKey - = new HashMap(); + private static class HierarchyInfo implements AttributeIndexingTarget { + private final String hierarchyKey; + private final EntityHierarchySource hierarchySource; private final Map> identifierAttributeSourcesByNature = new EnumMap>( SingularAttributeNature.class ); - private final Map> nonMappedBySingularAttributeSourcesByNature + + private HierarchyInfo(String hierarchyKey, EntityHierarchySource hierarchySource) { + this.hierarchyKey = hierarchyKey; + this.hierarchySource = hierarchySource; + } + + + public Map getSingularAttributeSources( + SingularAttributeNature singularAttributeNature) { + return identifierAttributeSourcesByNature.get( singularAttributeNature ); + } + + @Override + public void indexSingularAttributeSource(SingularAttributeSource attributeSource) { + if ( attributeSource.getSingularAttributeNature() == null ) { + ( (ToOneAttributeSource) attributeSource ).resolveToOneAttributeSourceNatureAsPartOfIdentifier(); + if ( attributeSource.getSingularAttributeNature() == null ) { + throw new IllegalStateException( + "Could not determine to-one association nature for [" + + attributeSource.getAttributeRole().getFullPath() + "]" + ); + } + } + + if ( ToOneAttributeSource.class.isInstance( attributeSource ) + && ToOneAttributeSource.class.cast( attributeSource ).isMappedBy() ) { + throw new IllegalStateException( + "Association attribute (to-one) that is part of an identifier " + + "cannot be mapped as mappedBy : " + + attributeSource.getAttributeRole().getFullPath() + ); + } + + Map natureMap = + identifierAttributeSourcesByNature.get( attributeSource.getSingularAttributeNature() ); + if ( natureMap == null ) { + natureMap = new HashMap(); + identifierAttributeSourcesByNature.put( attributeSource.getSingularAttributeNature(), natureMap ); + } + natureMap.put( attributeSource.getAttributeRole(), attributeSource ); + } + + @Override + public void indexPluralAttributeSource(PluralAttributeSource attributeSource) { + throw new AssertionFailure( + String.format( + "Identifiers should not contain plural attributes: [%s]", + attributeSource.getAttributeRole().getFullPath() + ) + ); + } + } + + private static class EntitySourceIndex implements AttributeIndexingTarget { + private final SourceIndex sourceIndex; + private final HierarchyInfo hierarchyInfo; + private final EntitySource entitySource; + + private final Map unresolvedSingularAttributeSourcesByKey + = new HashMap(); + + private final EnumMap> nonMappedBySingularAttributeSourcesByNature = new EnumMap>( SingularAttributeNature.class ); - private final Map> mappedBySingularAttributeSourcesByNature + private final EnumMap> mappedBySingularAttributeSourcesByNature = new EnumMap>( SingularAttributeNature.class ); // TODO: the following should not need to be LinkedHashMap, but it appears that some unit tests @@ -239,18 +570,24 @@ public class SourceIndex { private final Map inversePluralAttributeSourcesByKey = new LinkedHashMap(); + private EntitySourceIndex( + final SourceIndex sourceIndex, + final HierarchyInfo hierarchyInfo, + final EntitySource entitySource) { + this.sourceIndex = sourceIndex; + this.hierarchyInfo = hierarchyInfo; + this.entitySource = entitySource; + } + @Override - public void indexSingularAttributeSource(SingularAttributeSource attributeSource, boolean isInIdentifier) { + public void indexSingularAttributeSource(SingularAttributeSource attributeSource) { if ( attributeSource.getSingularAttributeNature() == null ) { unresolvedSingularAttributeSourcesByKey.put( attributeSource.getAttributeRole(), attributeSource ); return; } - final Map> map; - if ( isInIdentifier ) { - map = identifierAttributeSourcesByNature; - } - else if ( ToOneAttributeSource.class.isInstance( attributeSource ) && + final EnumMap> map; + if ( ToOneAttributeSource.class.isInstance( attributeSource ) && ToOneAttributeSource.class.cast( attributeSource ).isMappedBy() ) { map = mappedBySingularAttributeSourcesByNature; } @@ -261,9 +598,9 @@ public class SourceIndex { indexSingularAttributeSource( attributeSource, map ); } - private static void indexSingularAttributeSource( + protected static void indexSingularAttributeSource( SingularAttributeSource attributeSource, - Map> map) { + EnumMap> map) { final Map singularAttributeSources; if ( map.containsKey( attributeSource.getSingularAttributeNature() ) ) { singularAttributeSources = map.get( attributeSource.getSingularAttributeNature() ); @@ -272,7 +609,13 @@ public class SourceIndex { singularAttributeSources = new LinkedHashMap(); map.put( attributeSource.getSingularAttributeNature(), singularAttributeSources ); } - if ( singularAttributeSources.put( attributeSource.getAttributeRole(), attributeSource ) != null ) { + indexSingularAttributeSource( attributeSource, singularAttributeSources ); + } + + protected static void indexSingularAttributeSource( + SingularAttributeSource attributeSource, + Map singularAttributeSourceMap) { + if ( singularAttributeSourceMap.put( attributeSource.getAttributeRole(), attributeSource ) != null ) { throw new AssertionFailure( String.format( Locale.ENGLISH, @@ -377,7 +720,7 @@ public class SourceIndex { ); } ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) attributeSource; - toOneAttributeSource.resolveToOneAttributeSource( sourceResolutionContext ); + toOneAttributeSource.resolveToOneAttributeSourceNature( sourceResolutionContext ); if ( toOneAttributeSource.getSingularAttributeNature() == null ) { throw new AssertionFailure( String.format( @@ -396,84 +739,6 @@ public class SourceIndex { } } - protected abstract AttributeSourceResolutionContext makeAttributeSourceResolutionContext(BinderLocalBindingContext context); - } - - private static class HierarchyInfo extends AbstractAttributeIndexingTarget { - private final String hierarchyKey; - private final EntityHierarchySource hierarchySource; - - private HierarchyInfo(String hierarchyKey, EntityHierarchySource hierarchySource) { - this.hierarchyKey = hierarchyKey; - this.hierarchySource = hierarchySource; - } - - @Override - public void indexPluralAttributeSource(PluralAttributeSource attributeSource) { - throw new AssertionFailure( - String.format( - "Identifiers should not contain plural attributes: [%s]", - attributeSource.getAttributeRole().getFullPath() - ) - ); - } - - @Override - public Map getPluralAttributeSources(boolean isInverse) { - return Collections.emptyMap(); - } - - @Override - protected AttributeSourceResolutionContext makeAttributeSourceResolutionContext(final BinderLocalBindingContext context) { - return new AttributeSourceResolutionContext() { - @Override - public IdentifierSource resolveIdentifierSource(String entityName) { - return hierarchySource.getIdentifierSource(); - } - - @Override - public AttributeSource resolveAttributeSource(String entityName, String attributeName) { - throw new UnsupportedOperationException( "Whaaa!?!" ); - } - - @Override - public List resolveIdentifierColumns() { - return context.locateBinding( hierarchySource ).getRootEntityBinding().getPrimaryTable().getPrimaryKey().getColumns(); - } - }; - } - } - - private static class EntitySourceIndex extends AbstractAttributeIndexingTarget { - private final SourceIndex sourceIndex; - private final HierarchyInfo hierarchyInfo; - private final EntitySource entitySource; - - private EntitySourceIndex( - final SourceIndex sourceIndex, - final HierarchyInfo hierarchyInfo, - final EntitySource entitySource) { - this.sourceIndex = sourceIndex; - this.hierarchyInfo = hierarchyInfo; - this.entitySource = entitySource; - } - - @Override - public Map getSingularAttributeSources( - boolean isMappedBy, - SingularAttributeNature singularAttributeNature) { - Map values = hierarchyInfo.getSingularAttributeSources( - isMappedBy, - singularAttributeNature - ); - if ( values == null || values.isEmpty() ) { - values = super.getSingularAttributeSources( isMappedBy, singularAttributeNature ); - } - - return values; - } - - @Override protected AttributeSourceResolutionContext makeAttributeSourceResolutionContext( final BinderLocalBindingContext context) { return new AttributeSourceResolutionContext() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractIdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractIdentifierSource.java index 6ea1ed6318..10f0a3fb24 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractIdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractIdentifierSource.java @@ -26,60 +26,23 @@ package org.hibernate.metamodel.source.internal.annotations; import java.util.Collection; import java.util.Collections; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.internal.util.StringHelper; -import org.hibernate.metamodel.source.internal.annotations.util.JPADotNames; import org.hibernate.metamodel.source.spi.IdentifierSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; -import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationValue; - /** * @author Steve Ebersole */ public abstract class AbstractIdentifierSource implements IdentifierSource { private final RootEntitySourceImpl rootEntitySource; - private final Class lookupIdClass; protected AbstractIdentifierSource(RootEntitySourceImpl rootEntitySource) { this.rootEntitySource = rootEntitySource; - - this.lookupIdClass = resolveLookupIdClass( rootEntitySource ); - } - - private Class resolveLookupIdClass(RootEntitySourceImpl rootEntitySource) { - final AnnotationInstance idClassAnnotation = rootEntitySource.getEntityClass() - .getJavaTypeDescriptor() - .findTypeAnnotation( JPADotNames.ID_CLASS ); - if ( idClassAnnotation == null ) { - return null; - } - - final AnnotationValue idClassValue = idClassAnnotation.value(); - if ( idClassValue == null ) { - return null; - } - - final String idClassName = StringHelper.nullIfEmpty( idClassValue.asString() ); - if ( idClassName == null ) { - return null; - } - - return rootEntitySource.getLocalBindingContext().getServiceRegistry() - .getService( ClassLoaderService.class ) - .classForName( idClassName ); } protected RootEntitySourceImpl rootEntitySource() { return rootEntitySource; } - @Override - public Class getLookupIdClass() { - return lookupIdClass; - } - @Override public Collection getToolingHintSources() { return Collections.emptySet(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractToOneAttributeSourceImpl.java index d506b3f755..2eb6f88387 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AbstractToOneAttributeSourceImpl.java @@ -18,9 +18,6 @@ import org.hibernate.metamodel.spi.AttributeRole; import org.hibernate.metamodel.spi.SingularAttributeNature; import org.hibernate.type.ForeignKeyDirection; -import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationValue; - public abstract class AbstractToOneAttributeSourceImpl extends SingularAttributeSourceImpl implements ToOneAttributeSource{ private final SingularAssociationAttribute associationAttribute; private final Set unifiedCascadeStyles; @@ -28,14 +25,10 @@ public abstract class AbstractToOneAttributeSourceImpl extends SingularAttribute private SingularAttributeNature singularAttributeNature; private final Set ownedAssociationSources = new HashSet(); - private final MapsIdSourceImpl mapsIdSource; - public AbstractToOneAttributeSourceImpl(SingularAssociationAttribute associationAttribute) { super( associationAttribute ); this.associationAttribute = associationAttribute; this.unifiedCascadeStyles = determineCascadeStyles( associationAttribute ); - - this.mapsIdSource = MapsIdSourceImpl.interpret( associationAttribute.getMapsIdAnnotation() ); } private static Set determineCascadeStyles(SingularAssociationAttribute associationAttribute) { @@ -153,39 +146,4 @@ public abstract class AbstractToOneAttributeSourceImpl extends SingularAttribute public AttributeRole getAttributeRole() { return associationAttribute.getRole(); } - - @Override - public MapsIdSource getMapsIdSource() { - return mapsIdSource; - } - - private static class MapsIdSourceImpl implements MapsIdSource { - private final boolean present; - private final String name; - - public static MapsIdSourceImpl interpret(AnnotationInstance mapsIdAnnotation) { - if ( mapsIdAnnotation == null ) { - return new MapsIdSourceImpl( false, null ); - } - - final AnnotationValue value = mapsIdAnnotation.value(); - final String name = value == null ? null : value.asString(); - return new MapsIdSourceImpl( true, name ); - } - - private MapsIdSourceImpl(boolean present, String name) { - this.present = present; - this.name = name; - } - - @Override - public boolean isDefined() { - return present; - } - - @Override - public String getLookupClassAttributeName() { - return name; - } - } } \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AggregatedCompositeIdentifierSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AggregatedCompositeIdentifierSourceImpl.java index ca3b9e1e03..a5f8c283ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AggregatedCompositeIdentifierSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/AggregatedCompositeIdentifierSourceImpl.java @@ -25,10 +25,12 @@ package org.hibernate.metamodel.source.internal.annotations; import java.util.Collection; import java.util.Collections; +import java.util.List; import org.hibernate.id.EntityIdentifierNature; import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; @@ -42,12 +44,15 @@ class AggregatedCompositeIdentifierSourceImpl implements AggregatedCompositeIdentifierSource { private final EmbeddedAttributeSourceImpl componentAttributeSource; + private final List mapsIdSourceList; public AggregatedCompositeIdentifierSourceImpl( RootEntitySourceImpl rootEntitySource, - EmbeddedAttributeSourceImpl componentAttributeSource) { + EmbeddedAttributeSourceImpl componentAttributeSource, + List mapsIdSourceList) { super( rootEntitySource ); this.componentAttributeSource = componentAttributeSource; + this.mapsIdSourceList = mapsIdSourceList; } @Override @@ -55,6 +60,11 @@ class AggregatedCompositeIdentifierSourceImpl return componentAttributeSource; } + @Override + public List getMapsIdSources() { + return mapsIdSourceList; + } + @Override public IdentifierGeneratorDefinition getIndividualAttributeIdGenerator(String identifierAttributeName) { // for now, return null. this is that stupid specj bs @@ -77,11 +87,6 @@ class AggregatedCompositeIdentifierSourceImpl return null; } - @Override - public String getIdClassPropertyAccessorName() { - return componentAttributeSource.getPropertyAccessorName(); - } - @Override public Collection getToolingHintSources() { // not relevant for annotations diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntityHierarchySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntityHierarchySourceImpl.java index fa48b878de..4e8534242d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntityHierarchySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntityHierarchySourceImpl.java @@ -131,7 +131,8 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { case AGGREGATED: { return new AggregatedCompositeIdentifierSourceImpl( rootSource, - (EmbeddedAttributeSourceImpl) rootSource.getIdentifierAttributes().get( 0 ) + (EmbeddedAttributeSourceImpl) rootSource.getIdentifierAttributes().get( 0 ), + rootSource.getMapsIdSources() ); } case NON_AGGREGATED: { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntitySourceImpl.java index 0f9684a1dd..8d3f2e1d76 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/EntitySourceImpl.java @@ -224,7 +224,7 @@ public abstract class EntitySourceImpl extends IdentifiableTypeSourceAdapter imp } @Override - public LocalBindingContext getLocalBindingContext() { + public EntityBindingContext getLocalBindingContext() { return getEntityClass().getLocalBindingContext(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/HibernateTypeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/HibernateTypeSourceImpl.java index 48621c37bf..bf5fcc0928 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/HibernateTypeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/HibernateTypeSourceImpl.java @@ -23,55 +23,68 @@ */ package org.hibernate.metamodel.source.internal.annotations; +import java.util.Collections; import java.util.Map; -import org.hibernate.internal.util.ValueHolder; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.annotations.attribute.PersistentAttribute; import org.hibernate.metamodel.source.spi.HibernateTypeSource; +import org.hibernate.metamodel.source.spi.JavaTypeDescriptorResolvable; /** * @author Hardy Ferentschik * @author Strong Liu + * @author Steve Ebersole */ -public class HibernateTypeSourceImpl implements HibernateTypeSource { - private final ValueHolder nameHolder; - private final ValueHolder> parameterHolder; - private final JavaTypeDescriptor javaType; +public class HibernateTypeSourceImpl implements HibernateTypeSource, JavaTypeDescriptorResolvable { + private final String name; + private final Map parameters; + private JavaTypeDescriptor javaTypeDescriptor; - public HibernateTypeSourceImpl(final PersistentAttribute attribute) { - this.nameHolder = new ValueHolder( - new ValueHolder.DeferredInitializer() { - @Override - public String initialize() { - return attribute.getHibernateTypeResolver().getExplicitHibernateTypeName(); - } - } - ); - this.parameterHolder = new ValueHolder>( - new ValueHolder.DeferredInitializer>() { - @Override - public Map initialize() { - return attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters(); - } - } - ); - this.javaType = attribute.getBackingMember().getType().getErasedType(); + public HibernateTypeSourceImpl(PersistentAttribute attribute) { + this.name = attribute.getHibernateTypeResolver().getExplicitHibernateTypeName(); + this.parameters = attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters(); + this.javaTypeDescriptor = attribute.getBackingMember().getType().getErasedType(); + } + + public HibernateTypeSourceImpl(String name, Map parameters, JavaTypeDescriptor javaTypeDescriptor) { + this.name = name; + this.parameters = parameters; + this.javaTypeDescriptor = javaTypeDescriptor; + } + + public HibernateTypeSourceImpl() { + this( (String) null ); + } + + public HibernateTypeSourceImpl(String name) { + this.name = name; + this.parameters = Collections.emptyMap(); } @Override public String getName() { - return nameHolder.getValue(); + return name; } @Override public Map getParameters() { - return parameterHolder.getValue(); + return parameters; } @Override public JavaTypeDescriptor getJavaType() { - return javaType; + return javaTypeDescriptor; + } + + @Override + public void resolveJavaTypeDescriptor(JavaTypeDescriptor descriptor) { + if ( this.javaTypeDescriptor != null ) { + if ( this.javaTypeDescriptor != descriptor ) { + throw new IllegalStateException( "Attempt to resolve an already resolved JavaTypeDescriptor" ); + } + } + this.javaTypeDescriptor = descriptor; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/NonAggregatedCompositeIdentifierSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/NonAggregatedCompositeIdentifierSourceImpl.java index 2e5efb738d..4f4148ad7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/NonAggregatedCompositeIdentifierSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/NonAggregatedCompositeIdentifierSourceImpl.java @@ -27,17 +27,29 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.id.EntityIdentifierNature; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; +import org.hibernate.metamodel.reflite.spi.MemberDescriptor; +import org.hibernate.metamodel.source.internal.AttributeConversionInfo; +import org.hibernate.metamodel.source.internal.annotations.attribute.AssociationOverride; +import org.hibernate.metamodel.source.internal.annotations.attribute.AttributeOverride; +import org.hibernate.metamodel.source.internal.annotations.attribute.EmbeddedContainer; +import org.hibernate.metamodel.source.internal.annotations.entity.EmbeddableTypeMetadata; +import org.hibernate.metamodel.source.internal.annotations.entity.EntityBindingContext; import org.hibernate.metamodel.source.internal.annotations.util.JPADotNames; +import org.hibernate.metamodel.source.spi.AttributeSource; +import org.hibernate.metamodel.source.spi.EmbeddableSource; import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; +import org.hibernate.metamodel.spi.AttributePath; +import org.hibernate.metamodel.spi.AttributeRole; +import org.hibernate.metamodel.spi.NaturalIdMutability; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.DotName; +import org.jboss.logging.Logger; /** * @author Steve Ebersole @@ -45,26 +57,34 @@ import org.jboss.jandex.DotName; class NonAggregatedCompositeIdentifierSourceImpl extends AbstractIdentifierSource implements NonAggregatedCompositeIdentifierSource { + private static final Logger log = Logger.getLogger( NonAggregatedCompositeIdentifierSourceImpl.class ); - private final List idAttributes; - private final Class lookupIdClass; + private final List idAttributeSources; + private final IdClassSource idClassSource; public NonAggregatedCompositeIdentifierSourceImpl(RootEntitySourceImpl rootEntitySource) { super( rootEntitySource ); - this.idAttributes = rootEntitySource.getIdentifierAttributes(); + this.idAttributeSources = rootEntitySource.getIdentifierAttributes(); final JavaTypeDescriptor idClassDescriptor = resolveIdClassDescriptor(); if ( idClassDescriptor == null ) { - // probably this is an error... - this.lookupIdClass = null; + // todo : map this a MessageLogger message + log.warnf( + "Encountered non-aggregated identifier with no IdClass specified; while this is supported, " + + "its use should be considered deprecated" + ); + this.idClassSource = null; } else { - final ClassLoaderService cls = rootEntitySource.getLocalBindingContext() - .getServiceRegistry() - .getService( ClassLoaderService.class ); - this.lookupIdClass = cls.classForName( idClassDescriptor.getName().toString() ); + this.idClassSource = new IdClassSource( rootEntitySource, idClassDescriptor ); } + + + + + + } private JavaTypeDescriptor resolveIdClassDescriptor() { @@ -86,13 +106,13 @@ class NonAggregatedCompositeIdentifierSourceImpl } @Override - public Class getLookupIdClass() { - return lookupIdClass; + public List getAttributeSourcesMakingUpIdentifier() { + return idAttributeSources; } @Override - public String getIdClassPropertyAccessorName() { - return idAttributes.get( 0 ).getPropertyAccessorName(); + public EmbeddableSource getIdClassSource() { + return idClassSource; } @Override @@ -124,8 +144,159 @@ class NonAggregatedCompositeIdentifierSourceImpl return Collections.emptySet(); } - @Override - public List getAttributeSourcesMakingUpIdentifier() { - return idAttributes; + private class IdClassSource implements EmbeddableSource, EmbeddedContainer { + private final JavaTypeDescriptor idClassDescriptor; + private final EmbeddableTypeMetadata idClassTypeMetadata; + + private final AttributeRole attributeRoleBase; + private final AttributePath attributePathBase; + + private List attributeSources; + + private IdClassSource(RootEntitySourceImpl rootEntitySource, JavaTypeDescriptor idClassDescriptor) { + this.idClassDescriptor = idClassDescriptor; + + this.attributeRoleBase = rootEntitySource.getAttributeRoleBase().append( "" ); + this.attributePathBase = rootEntitySource.getAttributePathBase().append( "" ); + + final AnnotationAttributeSource firstIdAttribute = + (AnnotationAttributeSource) rootEntitySource.getIdentifierAttributes().get( 0 ); + + this.idClassTypeMetadata = new EmbeddableTypeMetadata( + idClassDescriptor, + this, + attributeRoleBase, + attributePathBase, + firstIdAttribute.getAnnotatedAttribute().getAccessType(), + null, + rootEntitySource.getLocalBindingContext() + ); + + // todo : locate MapsId annotations and build a specialized AttributeBuilder + + this.attributeSources = SourceHelper.buildAttributeSources( + idClassTypeMetadata, + SourceHelper.IdentifierPathAttributeBuilder.INSTANCE + ); + + if ( log.isDebugEnabled() ) { + String attributeDescriptors = null; + for ( AttributeSource attributeSource : attributeSources ) { + if ( attributeDescriptors == null ) { + attributeDescriptors = attributeSource.getName(); + } + else { + attributeDescriptors += ", " + attributeSource.getName(); + } + } + log.debugf( + "Built IdClassSource : %s : %s", + idClassTypeMetadata.getJavaTypeDescriptor().getName(), + attributeDescriptors + ); + } + + // todo : validate the IdClass attributes against the entity's id attributes + + // todo : we need similar (MapsId, validation) in the EmbeddedId case too. + } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return idClassDescriptor; + } + + @Override + public String getParentReferenceAttributeName() { + return null; + } + + @Override + public String getExplicitTuplizerClassName() { + return idClassTypeMetadata.getCustomTuplizerClassName(); + } + + @Override + public AttributePath getAttributePathBase() { + return attributePathBase; + } + + @Override + public AttributeRole getAttributeRoleBase() { + return attributeRoleBase; + } + + @Override + public List attributeSources() { + return attributeSources; + } + + @Override + public EntityBindingContext getLocalBindingContext() { + return idClassTypeMetadata.getLocalBindingContext(); + } + + // EmbeddedContainer impl (most of which we don't care about here + + @Override + public MemberDescriptor getBackingMember() { + return null; + } + + @Override + public AttributeConversionInfo locateConversionInfo(AttributePath attributePath) { + return null; + } + + @Override + public AttributeOverride locateAttributeOverride(AttributePath attributePath) { + return null; + } + + @Override + public AssociationOverride locateAssociationOverride( + AttributePath attributePath) { + return null; + } + + @Override + public NaturalIdMutability getContainerNaturalIdMutability() { + return null; + } + + @Override + public boolean getContainerOptionality() { + return false; + } + + @Override + public boolean getContainerUpdatability() { + return false; + } + + @Override + public boolean getContainerInsertability() { + return false; + } + + @Override + public void registerConverter( + AttributePath attributePath, AttributeConversionInfo conversionInfo) { + + } + + @Override + public void registerAttributeOverride( + AttributePath attributePath, AttributeOverride override) { + + } + + @Override + public void registerAssociationOverride( + AttributePath attributePath, AssociationOverride override) { + + } } + + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSequentialIndexSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSequentialIndexSourceImpl.java index 41fb821540..11e171ff6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSequentialIndexSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSequentialIndexSourceImpl.java @@ -25,15 +25,12 @@ package org.hibernate.metamodel.source.internal.annotations; import java.util.Collections; import java.util.List; -import java.util.Map; import org.hibernate.cfg.NamingStrategy; import org.hibernate.metamodel.internal.binder.Binder; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.annotations.attribute.Column; import org.hibernate.metamodel.source.internal.annotations.attribute.PluralAttribute; import org.hibernate.metamodel.source.internal.annotations.util.JPADotNames; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.PluralAttributeSequentialIndexSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.spi.PluralAttributeIndexNature; @@ -51,21 +48,7 @@ public class PluralAttributeSequentialIndexSourceImpl private final RelationalValueSource relationalValueSource; private final Binder.DefaultNamingStrategy defaultNamingStrategy; - private final static HibernateTypeSource INTEGER_TYPE = new HibernateTypeSource() { - @Override - public String getName() { - return "integer"; - } - - @Override - public Map getParameters() { - return Collections.emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; + private static HibernateTypeSourceImpl INTEGER_TYPE; public PluralAttributeSequentialIndexSourceImpl(final PluralAttribute attribute) { super( attribute ); @@ -81,6 +64,14 @@ public class PluralAttributeSequentialIndexSourceImpl return attribute.getName() + "_ORDER"; } }; + + if ( INTEGER_TYPE == null ) { + INTEGER_TYPE = new HibernateTypeSourceImpl( + "integer", + null, + attribute.getContext().typeDescriptor( "int" ) + ); + } } @Override @@ -99,7 +90,7 @@ public class PluralAttributeSequentialIndexSourceImpl } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return INTEGER_TYPE; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSourceImpl.java index 6ee85c21e1..25f812564a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSourceImpl.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Set; import org.hibernate.AssertionFailure; @@ -499,7 +498,7 @@ public class PluralAttributeSourceImpl private static class CollectionIdSourceImpl implements CollectionIdSource { private final ColumnSourceImpl columnSource; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; private final String generatorName; public CollectionIdSourceImpl(CollectionIdInformation collectionIdInformation, EntityBindingContext context) { @@ -520,69 +519,32 @@ public class PluralAttributeSourceImpl return new ColumnSourceImpl( columns.get( 0 ) ); } - private HibernateTypeSource createTypeSource(AttributeTypeResolver typeResolver) { + private HibernateTypeSourceImpl createTypeSource(AttributeTypeResolver typeResolver) { if ( typeResolver == null ) { - return EmptyHibernateTypeSource.INSTANCE; + return new HibernateTypeSourceImpl(); } final String resolvedTypeName = typeResolver.getExplicitHibernateTypeName(); if ( StringHelper.isEmpty( resolvedTypeName ) ) { - return EmptyHibernateTypeSource.INSTANCE; + return new HibernateTypeSourceImpl(); } - return new HibernateTypeSource() { - @Override - public String getName() { - return resolvedTypeName; - } - - @Override - public Map getParameters() { - return Collections.emptyMap(); - } - - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; + return new HibernateTypeSourceImpl( resolvedTypeName ); } @Override public ColumnSource getColumnSource() { - return null; + return columnSource; } @Override - public HibernateTypeSource getTypeInformation() { - return null; + public HibernateTypeSourceImpl getTypeInformation() { + return typeSource; } @Override public String getGeneratorName() { - return null; - } - } - - private static class EmptyHibernateTypeSource implements HibernateTypeSource { - /** - * Singleton access - */ - public static final EmptyHibernateTypeSource INSTANCE = new EmptyHibernateTypeSource(); - - @Override - public String getName() { - return null; - } - - @Override - public Map getParameters() { - return null; - } - - @Override - public JavaTypeDescriptor getJavaType() { - return null; + return generatorName; } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/RootEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/RootEntitySourceImpl.java index 9cda8bc130..756df564d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/RootEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/RootEntitySourceImpl.java @@ -25,8 +25,10 @@ package org.hibernate.metamodel.source.internal.annotations; import java.util.List; +import org.hibernate.metamodel.source.internal.annotations.attribute.SingularAssociationAttribute; import org.hibernate.metamodel.source.internal.annotations.entity.EntityBindingContext; import org.hibernate.metamodel.source.internal.annotations.entity.RootEntityTypeMetadata; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.TableSpecificationSource; @@ -42,6 +44,7 @@ import org.jboss.jandex.AnnotationInstance; */ public class RootEntitySourceImpl extends EntitySourceImpl { private List identifierAttributes; + private List mapsIdSources; /** * Constructs the root entity. Called from the construction of the @@ -71,12 +74,21 @@ public class RootEntitySourceImpl extends EntitySourceImpl { entityTypeMetadata, SourceHelper.IdentifierPathAttributeBuilder.INSTANCE ); + + this.mapsIdSources = SourceHelper.buildMapsIdSources( + entityTypeMetadata, + SourceHelper.IdentifierPathAttributeBuilder.INSTANCE + ); } public List getIdentifierAttributes() { return identifierAttributes; } + public List getMapsIdSources() { + return mapsIdSources; + } + @Override public RootEntityTypeMetadata getEntityClass() { return (RootEntityTypeMetadata) super.getEntityClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SimpleIdentifierSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SimpleIdentifierSourceImpl.java index a50edbf7b5..f772705625 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SimpleIdentifierSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SimpleIdentifierSourceImpl.java @@ -62,11 +62,6 @@ public class SimpleIdentifierSourceImpl extends AbstractIdentifierSource impleme public String getUnsavedValue() { return null; } - - @Override - public String getIdClassPropertyAccessorName() { - return attributeSource.getPropertyAccessorName(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SourceHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SourceHelper.java index 67c936af57..021cbe56c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SourceHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/SourceHelper.java @@ -31,6 +31,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.source.internal.annotations.attribute.BasicAttribute; import org.hibernate.metamodel.source.internal.annotations.attribute.EmbeddedAttribute; import org.hibernate.metamodel.source.internal.annotations.attribute.OverrideAndConverterCollector; @@ -44,10 +45,13 @@ import org.hibernate.metamodel.source.internal.annotations.entity.MappedSupercla import org.hibernate.metamodel.source.internal.annotations.entity.RootEntityTypeMetadata; import org.hibernate.metamodel.source.spi.AttributeSource; import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.PluralAttributeSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.ToOneAttributeSource; +import org.jboss.jandex.AnnotationValue; + /** * Utilities for building attribute source objects. * @@ -236,6 +240,37 @@ public class SourceHelper { } } + public static List buildMapsIdSources( + RootEntityTypeMetadata entityTypeMetadata, + IdentifierPathAttributeBuilder attributeBuilder) { + final List result = new ArrayList(); + for ( final SingularAssociationAttribute attribute : entityTypeMetadata.getMapsIdAttributes() ) { + final ToOneAttributeSource attributeSource = attributeBuilder.buildToOneAttribute( + attribute, + entityTypeMetadata + ); + + final AnnotationValue mapsIdNameValue = attribute.getMapsIdAnnotation().value(); + final String mappedIdAttributeName = mapsIdNameValue == null + ? null + : StringHelper.nullIfEmpty( mapsIdNameValue.asString() ); + result.add( + new MapsIdSource() { + @Override + public String getMappedIdAttributeName() { + return mappedIdAttributeName; + } + + @Override + public ToOneAttributeSource getAssociationAttributeSource() { + return attributeSource; + } + } + ); + } + return result; + } + public static interface AttributeBuilder { public SingularAttributeSource buildBasicAttribute( BasicAttribute attribute, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneAttributeSourceImpl.java index 2d0fd81ea4..a38791c8a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneAttributeSourceImpl.java @@ -59,6 +59,7 @@ import org.jboss.jandex.AnnotationInstance; /** * @author Hardy Ferentschik * @author Gail Badner + * @author Steve Ebersole */ public class ToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl implements ToOneAttributeSource { private final List relationalValueSources; @@ -108,6 +109,10 @@ public class ToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl i } else if ( associationAttribute.isId() ) { // if this association is part of the ID then this can't be a one-to-one + // todo : not strictly true... + // it *could* be a one-to-one if this is only value/attribute + // making up the identifier but legacy mapping did not support + // that, so supporting that would be a new feature return SingularAttributeNature.MANY_TO_ONE; } else if ( associationAttribute.getJoinColumnValues() == null || @@ -125,42 +130,51 @@ public class ToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl i } @Override - public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) { + public void resolveToOneAttributeSourceNature(AttributeSourceResolutionContext context) { if ( getSingularAttributeNature() != null ) { return; } - // It would be nice to have the following block in determineNatureIfPossible(), - // but it requires context.resolveIdentifierColumns(), it's here instead. - if ( AbstractPersistentAttribute.Nature.ONE_TO_ONE.equals( associationAttribute().getNature() ) ) { - final List idColumns = context.resolveIdentifierColumns(); - if ( associationAttribute().getJoinColumnValues().size() != idColumns.size() ) { - setSingularAttributeNature( SingularAttributeNature.MANY_TO_ONE ); - } - else { - Set joinColumnNames = new HashSet( associationAttribute().getJoinColumnValues().size() ); - for ( Column joinColumn : associationAttribute().getJoinColumnValues() ) { - joinColumnNames.add( joinColumn.getName() ); - } - // if join columns are the entity's ID, then it is a one-to-one (mapToPk == true) - boolean areJoinColumnsSameAsIdColumns = true; - for ( org.hibernate.metamodel.spi.relational.Column idColumn : idColumns ) { - if ( ! joinColumnNames.contains( idColumn.getColumnName().getText() ) ) { - areJoinColumnsSameAsIdColumns = false; - break; - } - } - setSingularAttributeNature( - areJoinColumnsSameAsIdColumns ? - SingularAttributeNature.ONE_TO_ONE : - SingularAttributeNature.MANY_TO_ONE - ); - } + + final List idColumns = context.resolveIdentifierColumns(); + if ( associationAttribute().getJoinColumnValues().size() != idColumns.size() ) { + setSingularAttributeNature( SingularAttributeNature.MANY_TO_ONE ); } + else { + Set joinColumnNames = new HashSet( associationAttribute().getJoinColumnValues().size() ); + for ( Column joinColumn : associationAttribute().getJoinColumnValues() ) { + joinColumnNames.add( joinColumn.getName() ); + } + // if join columns are the entity's ID, then it is a one-to-one (mapToPk == true) + boolean areJoinColumnsSameAsIdColumns = true; + for ( org.hibernate.metamodel.spi.relational.Column idColumn : idColumns ) { + if ( ! joinColumnNames.contains( idColumn.getColumnName().getText() ) ) { + areJoinColumnsSameAsIdColumns = false; + break; + } + } + setSingularAttributeNature( + areJoinColumnsSameAsIdColumns + ? SingularAttributeNature.ONE_TO_ONE + : SingularAttributeNature.MANY_TO_ONE + ); + } + if ( getSingularAttributeNature() == null ) { throw new NotYetImplementedException( "unknown type of to-one attribute." ); } } + @Override + public void resolveToOneAttributeSourceNatureAsPartOfIdentifier() { + if ( getSingularAttributeNature() != null ) { + return; + } + + // atm, always treated as a MANY_TO_ONE + // todo see note/todo in #determineNatureIfPossible + setSingularAttributeNature( SingularAttributeNature.MANY_TO_ONE ); + } + @Override public List getDefaultNamingStrategies( final String entityName, @@ -309,10 +323,9 @@ public class ToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl i @Override public List getJoinColumns(JoinColumnResolutionContext context) { final List values = new ArrayList(); - final List joinColumns = - associationAttribute().getJoinTableAnnotation() == null ? - associationAttribute().getJoinColumnValues() : - associationAttribute().getInverseJoinColumnValues(); + final List joinColumns = associationAttribute().getJoinTableAnnotation() == null + ? associationAttribute().getJoinColumnValues() + : associationAttribute().getInverseJoinColumnValues(); for ( Column joinColumn : joinColumns ) { if ( joinColumn.getReferencedColumnName() == null ) { return context.resolveRelationalValuesForAttribute( null ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneMappedByAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneMappedByAttributeSourceImpl.java index e0d07dc324..6da3d5f293 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneMappedByAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/ToOneMappedByAttributeSourceImpl.java @@ -62,7 +62,7 @@ public class ToOneMappedByAttributeSourceImpl } @Override - public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) { + public void resolveToOneAttributeSourceNature(AttributeSourceResolutionContext context) { if ( getSingularAttributeNature() != null && owner != null) { return; } @@ -96,6 +96,11 @@ public class ToOneMappedByAttributeSourceImpl } } + @Override + public void resolveToOneAttributeSourceNatureAsPartOfIdentifier() { + // should this be an error? + } + @Override public boolean isMappedBy() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/EmbeddableTypeMetadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/EmbeddableTypeMetadata.java index e82c503f85..f51912e092 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/EmbeddableTypeMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/EmbeddableTypeMetadata.java @@ -101,11 +101,14 @@ public class EmbeddableTypeMetadata extends ManagedTypeMetadata { private String decodeTuplizerAnnotation(EmbeddedContainer container) { // prefer tuplizer defined at the embedded level { - final AnnotationInstance tuplizerAnnotation = container.getBackingMember().getAnnotations().get( - HibernateDotNames.TUPLIZER - ); - if ( tuplizerAnnotation != null ) { - return tuplizerAnnotation.value( "impl" ).asString(); + // might be null though in the case of an IdClass + if ( container.getBackingMember() != null ) { + final AnnotationInstance tuplizerAnnotation = container.getBackingMember().getAnnotations().get( + HibernateDotNames.TUPLIZER + ); + if ( tuplizerAnnotation != null ) { + return tuplizerAnnotation.value( "impl" ).asString(); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/IdentifiableTypeMetadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/IdentifiableTypeMetadata.java index bf09efbf0c..569e0cd2a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/IdentifiableTypeMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/IdentifiableTypeMetadata.java @@ -42,6 +42,7 @@ import org.hibernate.metamodel.source.internal.annotations.attribute.Association import org.hibernate.metamodel.source.internal.annotations.attribute.AttributeOverride; import org.hibernate.metamodel.source.internal.annotations.attribute.BasicAttribute; import org.hibernate.metamodel.source.internal.annotations.attribute.PersistentAttribute; +import org.hibernate.metamodel.source.internal.annotations.attribute.SingularAssociationAttribute; import org.hibernate.metamodel.source.internal.annotations.attribute.SingularAttribute; import org.hibernate.metamodel.source.internal.annotations.util.JPADotNames; import org.hibernate.metamodel.source.internal.annotations.util.JPAListenerHelper; @@ -67,6 +68,7 @@ public class IdentifiableTypeMetadata extends ManagedTypeMetadata { private IdType idType; private List identifierAttributes; + private List mapsIdAssociationAttributes; private BasicAttribute versionAttribute; private final Map conversionInfoMap = new HashMap(); @@ -418,6 +420,17 @@ public class IdentifiableTypeMetadata extends ManagedTypeMetadata { identifierAttributes.add( singularAttribute ); return; } + + if ( SingularAssociationAttribute.class.isInstance( singularAttribute ) ) { + final SingularAssociationAttribute toOneAttribute = (SingularAssociationAttribute) singularAttribute; + if ( toOneAttribute.getMapsIdAnnotation() != null ) { + if ( mapsIdAssociationAttributes == null ) { + mapsIdAssociationAttributes = new ArrayList(); + } + mapsIdAssociationAttributes.add( toOneAttribute ); + return; + } + } } super.categorizeAttribute( persistentAttribute ); @@ -446,6 +459,19 @@ public class IdentifiableTypeMetadata extends ManagedTypeMetadata { return identifierAttributes == null ? Collections.emptyList() : identifierAttributes; } + public List getMapsIdAttributes() { + collectAttributesIfNeeded(); + + if ( mapsIdAssociationAttributes == null ) { + return getSuperType() != null + ? getSuperType().getMapsIdAttributes() + : Collections.emptyList(); + } + else { + return mapsIdAssociationAttributes; + } + } + public BasicAttribute getVersionAttribute() { collectAttributesIfNeeded(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/ManagedTypeMetadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/ManagedTypeMetadata.java index d925fb12b1..520028a250 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/ManagedTypeMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/entity/ManagedTypeMetadata.java @@ -355,14 +355,28 @@ public abstract class ManagedTypeMetadata implements OverrideAndConverterCollect final ClassDescriptor subclassTypeDescriptor = (ClassDescriptor) bindingContext.getJavaTypeDescriptorRepository().getType( classInfo.name() ); final IdentifiableTypeMetadata subclassMeta; - if ( isMappedSuperclass( javaTypeDescriptor ) ) { - subclassMeta = new MappedSuperclassTypeMetadata( subclassTypeDescriptor, superType, defaultAccessType, bindingContext ); + if ( isEntity( subclassTypeDescriptor ) ) { + subclassMeta = new EntityTypeMetadata( + subclassTypeDescriptor, + superType, + defaultAccessType, + bindingContext + ); + ( (ManagedTypeMetadata) superType ).addSubclass( subclassMeta ); + } + else if ( isMappedSuperclass( subclassTypeDescriptor ) ) { + subclassMeta = new MappedSuperclassTypeMetadata( + subclassTypeDescriptor, + superType, + defaultAccessType, + bindingContext + ); + ( (ManagedTypeMetadata) superType ).addSubclass( subclassMeta ); } else { - subclassMeta = new EntityTypeMetadata( subclassTypeDescriptor, superType, defaultAccessType, bindingContext ); + subclassMeta = superType; } - ( (ManagedTypeMetadata) superType ).addSubclass( subclassMeta ); walkSubclasses( subclassTypeDescriptor, subclassMeta, defaultAccessType, bindingContext ); } } @@ -416,18 +430,14 @@ public abstract class ManagedTypeMetadata implements OverrideAndConverterCollect protected void collectAttributesIfNeeded() { if ( persistentAttributeMap == null ) { persistentAttributeMap = new HashMap(); - // TODO: This probably isn't the best place for this. Walking and creating the ManagedTypeMetadatas, - // for the entire subclass tree, including subclasses that are not an @Entity/@MappedSuperclass/@Embeddable, - // is entirely necessary. But, we need to skip processing the attributes in this case. Cleaner way to do - // it in the new architecture? - if (isEntity( javaTypeDescriptor ) - || isMappedSuperclass( javaTypeDescriptor ) - || isEmbeddableType( javaTypeDescriptor )) { - collectPersistentAttributes(); - } + collectPersistentAttributes(); } } + public AccessType getClassLevelAccessType() { + return classLevelAccessType; + } + public String getCustomTuplizerClassName() { return customTuplizerClassName; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/global/SqlResultSetProcessor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/global/SqlResultSetProcessor.java index 321e743a22..4446ff03d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/global/SqlResultSetProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/global/SqlResultSetProcessor.java @@ -48,6 +48,7 @@ import org.hibernate.metamodel.source.internal.annotations.util.JandexHelper; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding; import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; @@ -283,14 +284,21 @@ public class SqlResultSetProcessor { // case COMPOSITE: // referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().isSingleAttribute();//.isIdentifierMapper(); // } + //todo check if this logic is correct - SingularAttributeBinding identifierAttributeBinding = referencedEntityBinding.getHierarchyDetails() - .getEntityIdentifier() - .getAttributeBinding(); - if ( EmbeddedAttributeBinding.class.isInstance( identifierAttributeBinding ) ) { - attributeBindings = EmbeddedAttributeBinding.class.cast( identifierAttributeBinding ) - .getEmbeddableBinding() - .attributeBindings(); + final EntityIdentifier idInfo = referencedEntityBinding.getHierarchyDetails() + .getEntityIdentifier(); + + if ( EntityIdentifier.AggregatedCompositeIdentifierBinding.class.isInstance( idInfo.getEntityIdentifierBinding() ) ) { + final EntityIdentifier.AggregatedCompositeIdentifierBinding identifierBinding = + (EntityIdentifier.AggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + attributeBindings = identifierBinding.getAttributeBinding() + .getEmbeddableBinding().attributeBindings(); + } + else if ( EntityIdentifier.NonAggregatedCompositeIdentifierBinding.class.isInstance( idInfo.getEntityIdentifierBinding() ) ) { + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding identifierBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + attributeBindings = identifierBinding.getVirtualEmbeddableBinding().attributeBindings(); } else { throw new MappingException( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/util/AssociationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/util/AssociationHelper.java index 15192fdd01..cfa250110d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/util/AssociationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/util/AssociationHelper.java @@ -268,8 +268,8 @@ public class AssociationHelper { } // only valid for to-one associations - if ( !PersistentAttribute.Nature.MANY_TO_ONE.equals( attributeNature ) - && !PersistentAttribute.Nature.MANY_TO_ONE.equals( attributeNature ) ) { + if ( PersistentAttribute.Nature.MANY_TO_ONE != attributeNature + && PersistentAttribute.Nature.ONE_TO_ONE != attributeNature ) { throw localBindingContext.makeMappingException( "@MapsId can only be specified on a many-to-one or one-to-one " + "associations, property: " + member.toString() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractPluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractPluralAttributeSourceImpl.java index a13f1e55fe..da2d128037 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractPluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractPluralAttributeSourceImpl.java @@ -92,21 +92,7 @@ public abstract class AbstractPluralAttributeSourceImpl this.caching = Helper.createCaching( pluralAttributeElement.getCache() ); - this.typeInformation = new HibernateTypeSource() { - @Override - public String getName() { - return pluralAttributeElement.getCollectionType(); - } - - @Override - public Map getParameters() { - return Collections.emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; + this.typeInformation = new HibernateTypeSourceImpl( pluralAttributeElement.getCollectionType() ); this.filterSources = buildFilterSources(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractToOneAttributeSourceImpl.java index fb43398286..c71a0c6a08 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/AbstractToOneAttributeSourceImpl.java @@ -35,7 +35,6 @@ import org.hibernate.mapping.PropertyGeneration; import org.hibernate.metamodel.internal.binder.Binder; import org.hibernate.metamodel.source.spi.AttributeSource; import org.hibernate.metamodel.source.spi.AttributeSourceResolutionContext; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.MappedByAssociationSource; import org.hibernate.metamodel.source.spi.MappingException; import org.hibernate.metamodel.source.spi.ToOneAttributeSource; @@ -60,11 +59,6 @@ public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSource super( sourceMappingDocument ); this.naturalIdMutability = naturalIdMutability; this.propertyRef = propertyRef; - - } - @Override - public HibernateTypeSource getTypeInformation() { - return Helper.TO_ONE_ATTRIBUTE_TYPE_SOURCE; } @Override @@ -229,7 +223,12 @@ public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSource } @Override - public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) { + public void resolveToOneAttributeSourceNature(AttributeSourceResolutionContext context) { + // nothing to do + } + + @Override + public void resolveToOneAttributeSourceNatureAsPartOfIdentifier() { // nothing to do } @@ -268,26 +267,4 @@ public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSource // TODO: Can HBM do something like JPA's @ForeignKey(NO_CONSTRAINT)? return true; } - - @Override - public MapsIdSource getMapsIdSource() { - return MapsIdSourceImpl.INSTANCE; - } - - private static class MapsIdSourceImpl implements MapsIdSource { - /** - * Singleton access - */ - public static final MapsIdSourceImpl INSTANCE = new MapsIdSourceImpl(); - - @Override - public boolean isDefined() { - return false; - } - - @Override - public String getLookupClassAttributeName() { - return null; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/EntityHierarchySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/EntityHierarchySourceImpl.java index 2a60d62bd3..d0f76c62c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/EntityHierarchySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/EntityHierarchySourceImpl.java @@ -25,6 +25,7 @@ package org.hibernate.metamodel.source.internal.hbm; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import org.hibernate.EntityMode; @@ -32,6 +33,7 @@ import org.hibernate.TruthValue; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbClassElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbCompositeIdElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbDiscriminatorElement; @@ -40,12 +42,16 @@ import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbKeyPropertyElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbMultiTenancyElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbPolymorphismAttribute; import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource; +import org.hibernate.metamodel.source.spi.AttributeSource; +import org.hibernate.metamodel.source.spi.AttributeSourceContainer; import org.hibernate.metamodel.source.spi.DiscriminatorSource; +import org.hibernate.metamodel.source.spi.EmbeddableSource; import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource; import org.hibernate.metamodel.source.spi.EntityHierarchySource; import org.hibernate.metamodel.source.spi.EntitySource; import org.hibernate.metamodel.source.spi.IdentifierSource; import org.hibernate.metamodel.source.spi.MappingException; +import org.hibernate.metamodel.source.spi.MapsIdSource; import org.hibernate.metamodel.source.spi.MultiTenancySource; import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; @@ -56,6 +62,7 @@ import org.hibernate.metamodel.source.spi.ToolingHintSource; import org.hibernate.metamodel.source.spi.VersionAttributeSource; import org.hibernate.metamodel.spi.AttributePath; import org.hibernate.metamodel.spi.AttributeRole; +import org.hibernate.metamodel.spi.LocalBindingContext; import org.hibernate.metamodel.spi.NaturalIdMutability; import org.hibernate.metamodel.spi.binding.Caching; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; @@ -121,7 +128,8 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { return new SimpleIdentifierSourceImpl(); } else { - // if we get here, we should have a composite identifier. Just need to determine if it is aggregated, or not... + // if we get here, we should have a composite identifier. Just need + // to determine if it is aggregated, or non-aggregated... if ( StringHelper.isEmpty( entityElement().getCompositeId().getName() ) ) { if ( entityElement().getCompositeId().isMapped() && StringHelper.isEmpty( entityElement().getCompositeId().getClazz() ) ) { @@ -391,16 +399,6 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { public Collection getToolingHintSources() { return entityElement().getId().getMeta(); } - - @Override - public Class getLookupIdClass() { - return determineJpaIdClass(); - } - - @Override - public String getIdClassPropertyAccessorName() { - return null; - } } private class AggregatedCompositeIdentifierSourceImpl implements AggregatedCompositeIdentifierSource { @@ -412,6 +410,11 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { return componentAttributeSource; } + @Override + public List getMapsIdSources() { + return Collections.emptyList(); + } + @Override public IdentifierGeneratorDefinition getIndividualAttributeIdGenerator(String identifierAttributeName) { // for now, return null. this is that stupid specj bs @@ -447,16 +450,6 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { return entityElement().getCompositeId().getUnsavedValue().value(); } - @Override - public Class getLookupIdClass() { - return determineJpaIdClass(); - } - - @Override - public String getIdClassPropertyAccessorName() { - return null; - } - @Override public Collection getToolingHintSources() { return entityElement().getId().getMeta(); @@ -529,49 +522,43 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { } } - private class NonAggregatedCompositeIdentifierSourceImpl implements NonAggregatedCompositeIdentifierSource { - @Override - public Class getLookupIdClass() { - return determineJpaIdClass(); + private final List attributeSources; + private final EmbeddableSource idClassSource; + + private NonAggregatedCompositeIdentifierSourceImpl() { + this.attributeSources = new ArrayList(); + collectCompositeIdAttributes( attributeSources, rootEntitySource ); + + // NOTE : the HBM support for IdClass is very limited. Essentially + // we assume that all identifier attributes occur in the IdClass + // using the same name and type. + this.idClassSource = interpretIdClass(); } - @Override - public String getIdClassPropertyAccessorName() { - return null; + private EmbeddableSource interpretIdClass() { + final JaxbCompositeIdElement compositeId = entityElement().getCompositeId(); + // if is null here we have much bigger problems :) + + final String className = compositeId.getClazz(); + if ( StringHelper.isEmpty( className ) ) { + return null; + } + + return new IdClassSource( rootEntitySource.getLocalBindingContext().typeDescriptor( className ) ); } @Override public List getAttributeSourcesMakingUpIdentifier() { - final List attributeSources = new ArrayList(); - final JaxbCompositeIdElement compositeId = entityElement().getCompositeId(); - final List list = compositeId.getKeyPropertyOrKeyManyToOne(); - for ( final Object obj : list ) { - if ( JaxbKeyPropertyElement.class.isInstance( obj ) ) { - JaxbKeyPropertyElement key = JaxbKeyPropertyElement.class.cast( obj ); - attributeSources.add( - new IdentifierKeyAttributeSourceImpl( - sourceMappingDocument(), - rootEntitySource, - key - ) - ); - } - if ( JaxbKeyManyToOneElement.class.isInstance( obj ) ) { - JaxbKeyManyToOneElement key = JaxbKeyManyToOneElement.class.cast( obj ); - attributeSources.add( - new IdentifierKeyManyToOneSourceImpl( - sourceMappingDocument(), - rootEntitySource, - key - ) - ); - } - } - return attributeSources; } + + @Override + public EmbeddableSource getIdClassSource() { + return idClassSource; + } + @Override public IdentifierGeneratorDefinition getIndividualAttributeIdGenerator(String identifierAttributeName) { // for now, return null. this is that stupid specj bs @@ -613,6 +600,81 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { } } + @SuppressWarnings("unchecked") + private void collectCompositeIdAttributes( + List attributeSources, + AttributeSourceContainer attributeSourceContainer) { + final JaxbCompositeIdElement compositeId = entityElement().getCompositeId(); + final List list = compositeId.getKeyPropertyOrKeyManyToOne(); + for ( final Object obj : list ) { + if ( JaxbKeyPropertyElement.class.isInstance( obj ) ) { + JaxbKeyPropertyElement key = JaxbKeyPropertyElement.class.cast( obj ); + attributeSources.add( + new IdentifierKeyAttributeSourceImpl( + sourceMappingDocument(), + attributeSourceContainer, + key + ) + ); + } + if ( JaxbKeyManyToOneElement.class.isInstance( obj ) ) { + JaxbKeyManyToOneElement key = JaxbKeyManyToOneElement.class.cast( obj ); + attributeSources.add( + new IdentifierKeyManyToOneSourceImpl( + sourceMappingDocument(), + attributeSourceContainer, + key + ) + ); + } + } + } + + private class IdClassSource implements EmbeddableSource { + private final JavaTypeDescriptor idClassDescriptor; + private final List attributeSources; + + private IdClassSource(JavaTypeDescriptor idClassDescriptor) { + this.idClassDescriptor = idClassDescriptor; + this.attributeSources = new ArrayList(); + collectCompositeIdAttributes( attributeSources, this ); + } + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return idClassDescriptor; + } + + @Override + public String getParentReferenceAttributeName() { + return null; + } + + @Override + public String getExplicitTuplizerClassName() { + return null; + } + + @Override + public AttributePath getAttributePathBase() { + return rootEntitySource.getAttributePathBase().append( "" ); + } + + @Override + public AttributeRole getAttributeRoleBase() { + return rootEntitySource.getAttributeRoleBase().append( "" ); + } + + @Override + public List attributeSources() { + return attributeSources; + } + + @Override + public LocalBindingContext getLocalBindingContext() { + return rootEntitySource.getLocalBindingContext(); + } + } + public static class EmbeddableJaxbSourceImpl extends AbstractEmbeddableJaxbSource { private final JaxbCompositeIdElement compositeIdElement; @@ -662,30 +724,6 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { } - private Class determineJpaIdClass() { - // this would be a defined with mapped="false" - final JaxbCompositeIdElement compositeId = entityElement().getCompositeId(); - if ( compositeId == null ) { - return null; - } - - if ( !"".equals( compositeId.getName() ) ) { - return null; - } - - if ( compositeId.isMapped() ) { - return null; - } - - if ( compositeId.getClazz() == null ) { - return null; - } - - // todo : do we really want to be loading this? - return rootEntitySource.bindingContext().getClassLoaderAccess().classForName( rootEntitySource.bindingContext().qualifyClassName( compositeId.getClazz() ) - ); - } - private String getEntityName() { return rootEntitySource.getEntityName(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/Helper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/Helper.java index 9b8e3570c9..336bf702b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/Helper.java @@ -68,22 +68,6 @@ import org.hibernate.metamodel.spi.binding.MetaAttribute; * @author Gail Badner */ public class Helper { - public static final HibernateTypeSource TO_ONE_ATTRIBUTE_TYPE_SOURCE = new HibernateTypeSource() { - @Override - public String getName() { - return null; - } - - @Override - public Map getParameters() { - return null; - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; - public static LockMode interpretLockMode(JaxbLockModeAttribute lockModeAttribute, LocalBindingContext context){ if ( lockModeAttribute == null ) { return LockMode.READ; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/HibernateTypeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/HibernateTypeSourceImpl.java new file mode 100644 index 0000000000..d2ee8caa37 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/HibernateTypeSourceImpl.java @@ -0,0 +1,83 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.source.internal.hbm; + +import java.util.Collections; +import java.util.Map; + +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; +import org.hibernate.metamodel.source.spi.HibernateTypeSource; +import org.hibernate.metamodel.source.spi.JavaTypeDescriptorResolvable; + +/** + * @author Steve Ebersole + */ +public class HibernateTypeSourceImpl implements HibernateTypeSource, JavaTypeDescriptorResolvable { + private final String name; + private final Map parameters; + private JavaTypeDescriptor javaTypeDescriptor; + + public HibernateTypeSourceImpl(String name) { + this( name, Collections.emptyMap() ); + } + + public HibernateTypeSourceImpl(String name, Map parameters) { + this.name = name; + this.parameters = parameters; + } + + public HibernateTypeSourceImpl(JavaTypeDescriptor javaTypeDescriptor) { + this( null, javaTypeDescriptor ); + } + + public HibernateTypeSourceImpl(String name, JavaTypeDescriptor javaTypeDescriptor) { + this( name ); + this.javaTypeDescriptor = javaTypeDescriptor; + } + + @Override + public String getName() { + return name; + } + + @Override + public Map getParameters() { + return parameters; + } + + @Override + public JavaTypeDescriptor getJavaType() { + return javaTypeDescriptor; + } + + @Override + public void resolveJavaTypeDescriptor(JavaTypeDescriptor descriptor) { + if ( this.javaTypeDescriptor != null ) { + if ( this.javaTypeDescriptor != descriptor ) { + throw new IllegalStateException( "Attempt to resolve an already resolved JavaTypeDescriptor" ); + } + } + this.javaTypeDescriptor = descriptor; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/IdBagSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/IdBagSourceImpl.java index 4c22365ba1..c3034e1e96 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/IdBagSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/IdBagSourceImpl.java @@ -23,18 +23,14 @@ */ package org.hibernate.metamodel.source.internal.hbm; -import java.util.Collections; import java.util.List; -import java.util.Map; import org.hibernate.internal.util.StringHelper; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbBagElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbIdbagElement; import org.hibernate.metamodel.source.spi.CollectionIdSource; import org.hibernate.metamodel.source.spi.ColumnSource; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.Orderable; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -100,25 +96,7 @@ public class IdBagSourceImpl extends AbstractPluralAttributeSourceImpl implement collectionIdColumnSource = (ColumnSource) relationalValueSource; } - final HibernateTypeSource typeSource = new HibernateTypeSource() { - private final String name = element.getCollectionId().getType(); - - @Override - public String getName() { - return name; - } - - @Override - public Map getParameters() { - return Collections.emptyMap(); - } - - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; - + final HibernateTypeSourceImpl typeSource = new HibernateTypeSourceImpl( element.getCollectionId().getType() ); this.collectionIdSource = new CollectionIdSourceImpl( collectionIdColumnSource, typeSource, @@ -148,12 +126,12 @@ public class IdBagSourceImpl extends AbstractPluralAttributeSourceImpl implement private static class CollectionIdSourceImpl implements CollectionIdSource { private final ColumnSource columnSource; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; private final String generator; public CollectionIdSourceImpl( ColumnSource columnSource, - HibernateTypeSource typeSource, + HibernateTypeSourceImpl typeSource, String generator) { this.columnSource = columnSource; this.typeSource = typeSource; @@ -166,7 +144,7 @@ public class IdBagSourceImpl extends AbstractPluralAttributeSourceImpl implement } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyAttributeSourceImpl.java index 21b27fd2d2..c1c874ab3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyAttributeSourceImpl.java @@ -28,11 +28,9 @@ import java.util.List; import java.util.Map; import org.hibernate.mapping.PropertyGeneration; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbKeyPropertyElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -52,7 +50,7 @@ class KeyAttributeSourceImpl implements SingularAttributeSource { private final JaxbKeyPropertyElement keyPropertyElement; private final NaturalIdMutability naturalIdMutability; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; private final List valueSources; private final AttributePath attributePath; @@ -65,30 +63,17 @@ class KeyAttributeSourceImpl super( mappingDocument ); this.keyPropertyElement = keyPropertyElement; this.naturalIdMutability = naturalIdMutability; - this.typeSource = new HibernateTypeSource() { - private final String name = keyPropertyElement.getTypeAttribute() != null - ? keyPropertyElement.getTypeAttribute() - : keyPropertyElement.getType() != null - ? keyPropertyElement.getType().getName() - : null; - private final Map parameters = ( keyPropertyElement.getType() != null ) - ? Helper.extractParameters( keyPropertyElement.getType().getParam() ) - : null; - @Override - public String getName() { - return name; - } + final String name = keyPropertyElement.getTypeAttribute() != null + ? keyPropertyElement.getTypeAttribute() + : keyPropertyElement.getType() != null + ? keyPropertyElement.getType().getName() + : null; + final Map parameters = ( keyPropertyElement.getType() != null ) + ? Helper.extractParameters( keyPropertyElement.getType().getParam() ) + : null; + this.typeSource = new HibernateTypeSourceImpl( name, parameters ); - @Override - public Map getParameters() { - return parameters; - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -144,7 +129,7 @@ class KeyAttributeSourceImpl } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyManyToOneSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyManyToOneSourceImpl.java index 2008fe4508..a1b726b141 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyManyToOneSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/KeyManyToOneSourceImpl.java @@ -30,6 +30,8 @@ import java.util.Set; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.CascadeStyles; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbKeyManyToOneElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; @@ -51,6 +53,7 @@ class KeyManyToOneSourceImpl extends AbstractToOneAttributeSourceImpl implements SingularAttributeSource { private final JaxbKeyManyToOneElement keyManyToOneElement; + private final HibernateTypeSourceImpl typeSource; private final List valueSources; private final AttributePath attributePath; @@ -63,6 +66,18 @@ class KeyManyToOneSourceImpl final NaturalIdMutability naturalIdMutability) { super( mappingDocument, naturalIdMutability, null ); this.keyManyToOneElement = keyManyToOneElement; + + final String referencedClassName = keyManyToOneElement.getClazz(); + JavaTypeDescriptor referencedClass = null; + if ( StringHelper.isNotEmpty( referencedClassName ) ) { + referencedClass = bindingContext().getJavaTypeDescriptorRepository().getType( + bindingContext().getJavaTypeDescriptorRepository().buildName( + bindingContext().qualifyClassName( keyManyToOneElement.getClazz() ) + ) + ); + } + this.typeSource = new HibernateTypeSourceImpl( referencedClass ); + this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -122,6 +137,11 @@ class KeyManyToOneSourceImpl return attributeRole; } + @Override + public HibernateTypeSourceImpl getTypeInformation() { + return typeSource; + } + @Override public String getPropertyAccessorName() { return keyManyToOneElement.getAccess(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/ManyToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/ManyToOneAttributeSourceImpl.java index 2339574c92..1d1d85c626 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/ManyToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/ManyToOneAttributeSourceImpl.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Set; import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbManyToOneElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; @@ -46,6 +48,8 @@ import org.hibernate.type.ForeignKeyDirection; */ class ManyToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { private final JaxbManyToOneElement manyToOneElement; + private final HibernateTypeSourceImpl typeSource; + private final String containingTableName; private final List valueSources; @@ -60,6 +64,18 @@ class ManyToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { NaturalIdMutability naturalIdMutability) { super( sourceMappingDocument, naturalIdMutability, manyToOneElement.getPropertyRef() ); this.manyToOneElement = manyToOneElement; + + final String referencedClassName = manyToOneElement.getClazz(); + JavaTypeDescriptor referencedClass = null; + if ( StringHelper.isNotEmpty( referencedClassName ) ) { + referencedClass = bindingContext().getJavaTypeDescriptorRepository().getType( + bindingContext().getJavaTypeDescriptorRepository().buildName( + bindingContext().qualifyClassName( manyToOneElement.getClazz() ) + ) + ); + } + this.typeSource = new HibernateTypeSourceImpl( referencedClass ); + this.containingTableName = logicalTableName; this.valueSources = Helper.buildValueSources( sourceMappingDocument(), @@ -120,6 +136,11 @@ class ManyToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { return attributeRole; } + @Override + public HibernateTypeSourceImpl getTypeInformation() { + return typeSource; + } + @Override public String getPropertyAccessorName() { return manyToOneElement.getAccess(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/MapKeySourceBasicImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/MapKeySourceBasicImpl.java index d71d59d693..9c128894e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/MapKeySourceBasicImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/MapKeySourceBasicImpl.java @@ -29,11 +29,9 @@ import java.util.Map; import org.hibernate.cfg.NamingStrategy; import org.hibernate.metamodel.internal.binder.Binder; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbIndexElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbMapKeyElement; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.PluralAttributeMapKeySourceBasic; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -45,11 +43,18 @@ import org.hibernate.metamodel.spi.PluralAttributeIndexNature; public class MapKeySourceBasicImpl extends AbstractHbmSourceNode implements PluralAttributeMapKeySourceBasic { private final PluralAttributeIndexNature nature; private final List valueSources; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; public MapKeySourceBasicImpl(MappingDocument sourceMappingDocument, final JaxbMapKeyElement mapKey) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( + + final String typeName = extractTypeName( mapKey ); + final Map typeParams = mapKey.getType() != null + ? Helper.extractParameters( mapKey.getType().getParam() ) + : java.util.Collections.emptyMap(); + this.typeSource = new HibernateTypeSourceImpl( typeName, typeParams ); + + this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -94,35 +99,25 @@ public class MapKeySourceBasicImpl extends AbstractHbmSourceNode implements Plur } } ); - this.typeSource = new HibernateTypeSource() { - @Override - public String getName() { - if ( mapKey.getTypeAttribute() != null ) { - return mapKey.getTypeAttribute(); - } - if ( mapKey.getType() != null ) { - return mapKey.getType().getName(); - } - return null; - } - @Override - public Map getParameters() { - return mapKey.getType() != null - ? Helper.extractParameters( mapKey.getType().getParam() ) - : java.util.Collections.emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; this.nature = PluralAttributeIndexNature.BASIC; } + private String extractTypeName(JaxbMapKeyElement mapKey) { + if ( mapKey.getTypeAttribute() != null ) { + return mapKey.getTypeAttribute(); + } + if ( mapKey.getType() != null ) { + return mapKey.getType().getName(); + } + return null; + } + public MapKeySourceBasicImpl(MappingDocument sourceMappingDocument, final JaxbIndexElement indexElement) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( + this.typeSource = new HibernateTypeSourceImpl( indexElement.getType() ); + + this.valueSources = Helper.buildValueSources( sourceMappingDocument, new Helper.ValueSourcesAdapter() { @@ -157,22 +152,6 @@ public class MapKeySourceBasicImpl extends AbstractHbmSourceNode implements Plur } } ); - typeSource = new HibernateTypeSource() { - @Override - public String getName() { - return indexElement.getType(); - } - - @Override - public Map getParameters() { - return java.util.Collections.emptyMap(); - } - - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; this.nature = PluralAttributeIndexNature.BASIC; } @@ -210,7 +189,7 @@ public class MapKeySourceBasicImpl extends AbstractHbmSourceNode implements Plur } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/OneToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/OneToOneAttributeSourceImpl.java index 756e69c23c..3b0ecfc618 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/OneToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/OneToOneAttributeSourceImpl.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Set; import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbOneToOneElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; @@ -43,11 +45,14 @@ import org.hibernate.type.ForeignKeyDirection; * Implementation for {@code } mappings * * @author Gail Badner + * @author Steve Ebersole */ class OneToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { private final JaxbOneToOneElement oneToOneElement; - private final List valueSources; + private final HibernateTypeSourceImpl typeSource; + private final String containingTableName; + private final List valueSources; private final AttributeRole attributeRole; private final AttributePath attributePath; @@ -60,6 +65,18 @@ class OneToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { NaturalIdMutability naturalIdMutability) { super( sourceMappingDocument, naturalIdMutability, oneToOneElement.getPropertyRef() ); this.oneToOneElement = oneToOneElement; + + final String referencedClassName = oneToOneElement.getClazz(); + JavaTypeDescriptor referencedClass = null; + if ( StringHelper.isNotEmpty( referencedClassName ) ) { + referencedClass = bindingContext().getJavaTypeDescriptorRepository().getType( + bindingContext().getJavaTypeDescriptorRepository().buildName( + bindingContext().qualifyClassName( oneToOneElement.getClazz() ) + ) + ); + } + this.typeSource = new HibernateTypeSourceImpl( referencedClass ); + this.containingTableName = logicalTableName; this.valueSources = Helper.buildValueSources( sourceMappingDocument(), @@ -122,6 +139,11 @@ class OneToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl { return attributeRole; } + @Override + public HibernateTypeSourceImpl getTypeInformation() { + return typeSource; + } + @Override public String getPropertyAccessorName() { return oneToOneElement.getAccess(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeElementSourceBasicImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeElementSourceBasicImpl.java index 3d39509534..2b506dc493 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeElementSourceBasicImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeElementSourceBasicImpl.java @@ -26,10 +26,8 @@ package org.hibernate.metamodel.source.internal.hbm; import java.util.List; import java.util.Map; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbElementElement; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.PluralAttributeElementSourceBasic; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -41,13 +39,20 @@ import org.hibernate.metamodel.spi.PluralAttributeElementNature; public class PluralAttributeElementSourceBasicImpl extends AbstractHbmSourceNode implements PluralAttributeElementSourceBasic { + private final HibernateTypeSourceImpl typeSource; private final List valueSources; - private final HibernateTypeSource typeSource; public PluralAttributeElementSourceBasicImpl( MappingDocument sourceMappingDocument, final JaxbElementElement elementElement) { super( sourceMappingDocument ); + + final String typeName = extractTypeName( elementElement ); + final Map typeParams = elementElement.getType() != null + ? Helper.extractParameters( elementElement.getType().getParam() ) + : java.util.Collections.emptyMap(); + this.typeSource = new HibernateTypeSourceImpl( typeName, typeParams ); + this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -96,32 +101,18 @@ public class PluralAttributeElementSourceBasicImpl } } ); + } - this.typeSource = new HibernateTypeSource() { - @Override - public String getName() { - if ( elementElement.getTypeAttribute() != null ) { - return elementElement.getTypeAttribute(); - } - else if ( elementElement.getType() != null ) { - return elementElement.getType().getName(); - } - else { - return null; - } - } - - @Override - public Map getParameters() { - return elementElement.getType() != null - ? Helper.extractParameters( elementElement.getType().getParam() ) - : java.util.Collections.emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; + private String extractTypeName(JaxbElementElement elementElement) { + if ( elementElement.getTypeAttribute() != null ) { + return elementElement.getTypeAttribute(); + } + else if ( elementElement.getType() != null ) { + return elementElement.getType().getName(); + } + else { + return null; + } } @Override @@ -150,7 +141,7 @@ public class PluralAttributeElementSourceBasicImpl } @Override - public HibernateTypeSource getExplicitHibernateTypeSource() { + public HibernateTypeSourceImpl getExplicitHibernateTypeSource() { return typeSource; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeSequentialIndexSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeSequentialIndexSourceImpl.java index c2dc88d14a..177710c37a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeSequentialIndexSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PluralAttributeSequentialIndexSourceImpl.java @@ -25,16 +25,13 @@ package org.hibernate.metamodel.source.internal.hbm; import java.util.Collections; import java.util.List; -import java.util.Map; import org.hibernate.cfg.NamingStrategy; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.internal.binder.Binder; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbIndexElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbListIndexElement; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.PluralAttributeSequentialIndexSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -43,110 +40,90 @@ import org.hibernate.metamodel.spi.PluralAttributeIndexNature; /** * */ -public class PluralAttributeSequentialIndexSourceImpl extends AbstractHbmSourceNode implements - PluralAttributeSequentialIndexSource { - private final List< RelationalValueSource > valueSources; - private final HibernateTypeSource typeSource; +public class PluralAttributeSequentialIndexSourceImpl + extends AbstractHbmSourceNode + implements PluralAttributeSequentialIndexSource { private final int base; + private final HibernateTypeSourceImpl typeSource; + private final List valueSources; public PluralAttributeSequentialIndexSourceImpl( MappingDocument sourceMappingDocument, final JaxbListIndexElement indexElement) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( sourceMappingDocument, new Helper.ValueSourcesAdapter() { - - List< JaxbColumnElement > columnElements = indexElement.getColumn() == null ? Collections.EMPTY_LIST : Collections.singletonList( indexElement.getColumn() ); - - @Override - public String getColumnAttribute() { - return indexElement.getColumnAttribute(); - } - - @Override - public List getColumn() { - return columnElements; - } - - @Override - public boolean isIncludedInInsertByDefault() { - return areValuesIncludedInInsertByDefault(); - } - - @Override - public boolean isIncludedInUpdateByDefault() { - return areValuesIncludedInUpdateByDefault(); - } - } ); - typeSource = new HibernateTypeSource() { - - @Override - public String getName() { - return "integer"; - } - - @Override - public Map< String, String > getParameters() { - return java.util.Collections.< String, String >emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; base = Integer.parseInt( indexElement.getBase() ); + typeSource = new HibernateTypeSourceImpl( "integer", bindingContext().typeDescriptor( "int" ) ); + valueSources = Helper.buildValueSources( + sourceMappingDocument, + new Helper.ValueSourcesAdapter() { + List columnElements = indexElement.getColumn() == null + ? Collections.emptyList() + : Collections.singletonList( indexElement.getColumn() ); + + @Override + public String getColumnAttribute() { + return indexElement.getColumnAttribute(); + } + + @Override + public List getColumn() { + return columnElements; + } + + @Override + public boolean isIncludedInInsertByDefault() { + return areValuesIncludedInInsertByDefault(); + } + + @Override + public boolean isIncludedInUpdateByDefault() { + return areValuesIncludedInUpdateByDefault(); + } + } + ); } public PluralAttributeSequentialIndexSourceImpl( MappingDocument sourceMappingDocument, final JaxbIndexElement indexElement) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( sourceMappingDocument, new Helper.ValueSourcesAdapter() { - - @Override - public String getColumnAttribute() { - return indexElement.getColumnAttribute(); - } - - @Override - public SizeSource getSizeSource() { - return Helper.createSizeSourceIfMapped( - indexElement.getLength(), - null, - null - ); - } - @Override - public List getColumn() { - return indexElement.getColumn(); - } - - @Override - public boolean isIncludedInInsertByDefault() { - return areValuesIncludedInInsertByDefault(); - } - - @Override - public boolean isIncludedInUpdateByDefault() { - return areValuesIncludedInUpdateByDefault(); - } - } ); - typeSource = new HibernateTypeSource() { - - @Override - public String getName() { - return StringHelper.isEmpty( indexElement.getType() ) ? "integer" : indexElement.getType(); - } - - @Override - public Map< String, String > getParameters() { - return java.util.Collections.< String, String >emptyMap(); - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; base = 0; + typeSource = new HibernateTypeSourceImpl( + StringHelper.isEmpty( indexElement.getType() ) ? "integer" : indexElement.getType(), + bindingContext().typeDescriptor( "int" ) + ); + valueSources = Helper.buildValueSources( + sourceMappingDocument, + new Helper.ValueSourcesAdapter() { + @Override + public String getColumnAttribute() { + return indexElement.getColumnAttribute(); + } + + @Override + public SizeSource getSizeSource() { + return Helper.createSizeSourceIfMapped( + indexElement.getLength(), + null, + null + ); + } + @Override + public List getColumn() { + return indexElement.getColumn(); + } + + @Override + public boolean isIncludedInInsertByDefault() { + return areValuesIncludedInInsertByDefault(); + } + + @Override + public boolean isIncludedInUpdateByDefault() { + return areValuesIncludedInUpdateByDefault(); + } + } + ); } @Override @@ -185,7 +162,7 @@ public class PluralAttributeSequentialIndexSourceImpl extends AbstractHbmSourceN } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PropertyAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PropertyAttributeSourceImpl.java index 8e8845e233..737f33b37f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PropertyAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/PropertyAttributeSourceImpl.java @@ -28,11 +28,9 @@ import java.util.List; import java.util.Map; import org.hibernate.mapping.PropertyGeneration; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbPropertyElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -49,7 +47,7 @@ import org.hibernate.metamodel.spi.SingularAttributeNature; */ class PropertyAttributeSourceImpl extends AbstractHbmSourceNode implements SingularAttributeSource { private final JaxbPropertyElement propertyElement; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; private final List valueSources; private final NaturalIdMutability naturalIdMutability; private final String containingTableName; @@ -65,30 +63,17 @@ class PropertyAttributeSourceImpl extends AbstractHbmSourceNode implements Singu NaturalIdMutability naturalIdMutability) { super( sourceMappingDocument ); this.propertyElement = propertyElement; - this.typeSource = new HibernateTypeSource() { - private final String name = propertyElement.getTypeAttribute() != null - ? propertyElement.getTypeAttribute() - : propertyElement.getType() != null - ? propertyElement.getType().getName() - : null; - private final Map parameters = ( propertyElement.getType() != null ) - ? Helper.extractParameters( propertyElement.getType().getParam() ) - : null; - @Override - public String getName() { - return name; - } + final String name = propertyElement.getTypeAttribute() != null + ? propertyElement.getTypeAttribute() + : propertyElement.getType() != null + ? propertyElement.getType().getName() + : null; + final Map parameters = ( propertyElement.getType() != null ) + ? Helper.extractParameters( propertyElement.getType().getParam() ) + : null; + this.typeSource = new HibernateTypeSourceImpl( name, parameters ); - @Override - public Map getParameters() { - return parameters; - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; this.containingTableName = logicalTableName; this.valueSources = Helper.buildValueSources( sourceMappingDocument(), @@ -162,7 +147,7 @@ class PropertyAttributeSourceImpl extends AbstractHbmSourceNode implements Singu } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/SingularIdentifierAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/SingularIdentifierAttributeSourceImpl.java index b6db4cf4f0..e56b8de7b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/SingularIdentifierAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/SingularIdentifierAttributeSourceImpl.java @@ -28,11 +28,9 @@ import java.util.List; import java.util.Map; import org.hibernate.mapping.PropertyGeneration; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbIdElement; import org.hibernate.metamodel.source.spi.AttributeSourceContainer; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.SingularAttributeSource; import org.hibernate.metamodel.source.spi.SizeSource; @@ -52,7 +50,7 @@ class SingularIdentifierAttributeSourceImpl implements SingularAttributeSource { private final JaxbIdElement idElement; - private final HibernateTypeSource typeSource; + private final HibernateTypeSourceImpl typeSource; private final List valueSources; private final AttributeRole attributeRole; @@ -64,31 +62,17 @@ class SingularIdentifierAttributeSourceImpl final JaxbIdElement idElement) { super( mappingDocument ); this.idElement = idElement; - this.typeSource = new HibernateTypeSource() { - private final String name = idElement.getTypeAttribute() != null - ? idElement.getTypeAttribute() - : idElement.getType() != null - ? idElement.getType().getName() - : null; - private final Map parameters = ( idElement.getType() != null ) - ? Helper.extractParameters( idElement.getType().getParam() ) - : null; - @Override - public String getName() { - return name; - } + final String name = idElement.getTypeAttribute() != null + ? idElement.getTypeAttribute() + : idElement.getType() != null + ? idElement.getType().getName() + : null; + final Map parameters = ( idElement.getType() != null ) + ? Helper.extractParameters( idElement.getType().getParam() ) + : null; + this.typeSource = new HibernateTypeSourceImpl( name, parameters ); - @Override - public Map getParameters() { - return parameters; - } - - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -145,7 +129,7 @@ class SingularIdentifierAttributeSourceImpl } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/TimestampAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/TimestampAttributeSourceImpl.java index fbdbd0ed9d..1a8204ef68 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/TimestampAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/TimestampAttributeSourceImpl.java @@ -25,13 +25,10 @@ package org.hibernate.metamodel.source.internal.hbm; import java.util.Collection; import java.util.List; -import java.util.Map; import org.hibernate.internal.util.ValueHolder; import org.hibernate.mapping.PropertyGeneration; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbTimestampElement; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; import org.hibernate.metamodel.source.spi.VersionAttributeSource; @@ -49,6 +46,8 @@ class TimestampAttributeSourceImpl extends AbstractHbmSourceNode implements VersionAttributeSource { private final JaxbTimestampElement timestampElement; + private final HibernateTypeSourceImpl typeSource; + private final List valueSources; private final AttributePath attributePath; @@ -60,6 +59,13 @@ class TimestampAttributeSourceImpl final JaxbTimestampElement timestampElement) { super( mappingDocument ); this.timestampElement = timestampElement; + + this.typeSource = new HibernateTypeSourceImpl( + "db".equals( timestampElement.getSource().value() ) + ? "dbtimestamp" + : "timestamp" + ); + this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -83,22 +89,6 @@ class TimestampAttributeSourceImpl this.attributeRole = rootEntitySource.getAttributeRoleBase().append( getName() ); } - private final HibernateTypeSource typeSource = new HibernateTypeSource() { - @Override - public String getName() { - return "db".equals( timestampElement.getSource() ) ? "dbtimestamp" : "timestamp"; - } - - @Override - public Map getParameters() { - return null; - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; - @Override public String getName() { return timestampElement.getName(); @@ -115,7 +105,7 @@ class TimestampAttributeSourceImpl } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/VersionAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/VersionAttributeSourceImpl.java index 1223d686bb..480eb4347c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/VersionAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/hbm/VersionAttributeSourceImpl.java @@ -25,14 +25,11 @@ package org.hibernate.metamodel.source.internal.hbm; import java.util.Collection; import java.util.List; -import java.util.Map; import org.hibernate.internal.util.ValueHolder; import org.hibernate.mapping.PropertyGeneration; -import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbColumnElement; import org.hibernate.metamodel.source.internal.jaxb.hbm.JaxbVersionElement; -import org.hibernate.metamodel.source.spi.HibernateTypeSource; import org.hibernate.metamodel.source.spi.RelationalValueSource; import org.hibernate.metamodel.source.spi.ToolingHintSource; import org.hibernate.metamodel.source.spi.VersionAttributeSource; @@ -51,6 +48,8 @@ class VersionAttributeSourceImpl extends AbstractHbmSourceNode implements VersionAttributeSource { private final JaxbVersionElement versionElement; + private final HibernateTypeSourceImpl typeSource; + private final List valueSources; private final AttributePath attributePath; @@ -62,6 +61,13 @@ class VersionAttributeSourceImpl final JaxbVersionElement versionElement) { super( mappingDocument ); this.versionElement = versionElement; + + this.typeSource = new HibernateTypeSourceImpl( + versionElement.getType() == null + ? "integer" + : versionElement.getType() + ); + this.valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { @@ -90,21 +96,6 @@ class VersionAttributeSourceImpl this.attributeRole = rootEntitySource.getAttributeRoleBase().append( getName() ); } - private final HibernateTypeSource typeSource = new HibernateTypeSource() { - @Override - public String getName() { - return versionElement.getType() == null ? "integer" : versionElement.getType(); - } - - @Override - public Map getParameters() { - return null; - } - @Override - public JavaTypeDescriptor getJavaType() { - return null; - } - }; @Override public String getUnsavedValue() { @@ -127,7 +118,7 @@ class VersionAttributeSourceImpl } @Override - public HibernateTypeSource getTypeInformation() { + public HibernateTypeSourceImpl getTypeInformation() { return typeSource; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/AggregatedCompositeIdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/AggregatedCompositeIdentifierSource.java index bbe2709bb9..42ca5d931f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/AggregatedCompositeIdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/AggregatedCompositeIdentifierSource.java @@ -23,10 +23,15 @@ */ package org.hibernate.metamodel.source.spi; +import java.util.List; + /** - * Additional contract describing the source of an identifier mapping whose {@link #getNature() nature} is - * {@link org.hibernate.id.EntityIdentifierNature#AGGREGATED_COMPOSITE aggregated-composite}. This equates to an identifier which is - * made up of multiple values which are defined as part of a component/embedded. + * Additional contract describing the source of an identifier mapping whose + * {@link #getNature() nature} is + * {@link org.hibernate.id.EntityIdentifierNature#AGGREGATED_COMPOSITE}. + *

    + * This equates to an identifier which is made up of multiple values which are + * defined as part of a component/embedded; i.e. {@link javax.persistence.EmbeddedId} * * @author Strong Liu * @author Steve Ebersole @@ -38,4 +43,11 @@ public interface AggregatedCompositeIdentifierSource extends CompositeIdentifier * @return The identifier attribute source. */ public EmbeddedAttributeSource getIdentifierAttributeSource(); + + /** + * Obtain the mapping of attributes annotated with {@link javax.persistence.MapsId}. + * + * @return The MapsId sources. + */ + public List getMapsIdSources(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/CompositeIdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/CompositeIdentifierSource.java index 8b484a2807..14c842409a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/CompositeIdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/CompositeIdentifierSource.java @@ -26,6 +26,10 @@ package org.hibernate.metamodel.source.spi; import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition; /** + * Common contract for composite identifiers. Specific sub-types include aggregated + * (think {@link javax.persistence.EmbeddedId}) and non-aggregated (think + * {@link javax.persistence.IdClass}). + * * @author Steve Ebersole */ public interface CompositeIdentifierSource extends IdentifierSource { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/IdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/IdentifierSource.java index b828eebad0..7408ed910b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/IdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/IdentifierSource.java @@ -59,19 +59,4 @@ public interface IdentifierSource extends ToolingHintSourceContainer { * @return the "unsaved" entity identifier value */ public String getUnsavedValue(); - - /** - * Retrieve the class specified as the {@link javax.persistence.IdClass}, if one. - * - * @return The class specified as the {@link javax.persistence.IdClass}, or {@code null} if none. - */ - public Class getLookupIdClass(); - - /** - * Obtain the property accessor name for the {@link javax.persistence.IdClass}, if one. - * - * @return The property accessor name for the {@link javax.persistence.IdClass}, or {@code null} if none. - **/ - public String getIdClassPropertyAccessorName(); - } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/JavaTypeDescriptorResolvable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/JavaTypeDescriptorResolvable.java new file mode 100644 index 0000000000..469268d062 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/JavaTypeDescriptorResolvable.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.source.spi; + +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public interface JavaTypeDescriptorResolvable { + public void resolveJavaTypeDescriptor(JavaTypeDescriptor descriptor); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MapsIdSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MapsIdSource.java new file mode 100644 index 0000000000..c49274dc2a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MapsIdSource.java @@ -0,0 +1,46 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.source.spi; + +/** + * Describes a relationship annotated with {@link javax.persistence.MapsId} + * + * @author Steve Ebersole + */ +public interface MapsIdSource { + /** + * Obtain the {@link javax.persistence.MapsId#value()} naming the attribute + * within the EmbeddedId mapped by this relationship. + * + * @return The corresponding id attribute name. + */ + public String getMappedIdAttributeName(); + + /** + * The attribute source information + * + * @return The association attribute information + */ + public ToOneAttributeSource getAssociationAttributeSource(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/NonAggregatedCompositeIdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/NonAggregatedCompositeIdentifierSource.java index 550a51eacf..8cf28bdcf2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/NonAggregatedCompositeIdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/NonAggregatedCompositeIdentifierSource.java @@ -28,6 +28,8 @@ import java.util.List; /** * Additional contract describing the source of an identifier mapping whose {@link #getNature() nature} is * {@link org.hibernate.id.EntityIdentifierNature#NON_AGGREGATED_COMPOSITE }. + *

    + * Think {@link javax.persistence.IdClass} * * @author Steve Ebersole */ @@ -38,4 +40,11 @@ public interface NonAggregatedCompositeIdentifierSource extends CompositeIdentif * @return The identifier attribute source. */ public List getAttributeSourcesMakingUpIdentifier(); + + /** + * Retrieve the source information for the {@link javax.persistence.IdClass} definition + * + * @return The IdClass source information, or {@code null} if none. + */ + public EmbeddableSource getIdClassSource(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSource.java index db1fea0aea..b20cae6872 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSource.java @@ -41,29 +41,9 @@ public interface ToOneAttributeSource FetchableAttributeSource, AssociationSource { - public MapsIdSource getMapsIdSource(); - public boolean isUnique(); public boolean isUnWrapProxy(); ForeignKeyDirection getForeignKeyDirection(); public List getDefaultNamingStrategies(final String entityName, final String tableName, final AttributeBinding referencedAttributeBinding); - /** - * Source for JPA {@link javax.persistence.MapsId} annotation information - */ - public static interface MapsIdSource { - /** - * Was a MapsId annotation present on the to-one? - * - * @return {@code true} if MapsId annotation was present; {@code false} otherwise. - */ - public boolean isDefined(); - - /** - * The {@link javax.persistence.MapsId#value()} value. - * - * @return The indicated name - */ - public String getLookupClassAttributeName(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSourceNatureResolver.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSourceNatureResolver.java index 7b251e8096..4bdf072767 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSourceNatureResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/ToOneAttributeSourceNatureResolver.java @@ -25,11 +25,12 @@ package org.hibernate.metamodel.source.spi; /** * @author Gail Badner + * @author Steve Ebersole */ public interface ToOneAttributeSourceNatureResolver { /** - * Perform any steps to completely resolve this attribute source. + * Perform any steps to completely resolve nature of this attribute source. * * If this is a {@link MappedByAssociationSource}, resolution must * resolve the association owner, and this association must be added @@ -37,5 +38,11 @@ public interface ToOneAttributeSourceNatureResolver { * * @param context */ - void resolveToOneAttributeSource(AttributeSourceResolutionContext context); + void resolveToOneAttributeSourceNature(AttributeSourceResolutionContext context); + + /** + * Like {@link #resolveToOneAttributeSourceNature} but specifically for to-one + * attributes that are part of an identifier. + */ + void resolveToOneAttributeSourceNatureAsPartOfIdentifier(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractAttributeKey.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractAttributeKey.java index 7f2eda3d70..68e0e71904 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractAttributeKey.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractAttributeKey.java @@ -32,11 +32,18 @@ public abstract class AbstractAttributeKey { private final AbstractAttributeKey parent; private final String property; private final String fullPath; + private final int depth; + /** + * Constructor for the base AttributePath + */ protected AbstractAttributeKey() { this( null, "" ); } + /** + * Constructor for the base AttributeRole + */ protected AbstractAttributeKey(String base) { this( null, base ); } @@ -54,14 +61,20 @@ public abstract class AbstractAttributeKey { else { prefix = resolvedParent + getDelimiter(); } + depth = parent.getDepth() + 1; } else { prefix = ""; + depth = 0; } this.fullPath = prefix + property; } + public int getDepth() { + return depth; + } + protected abstract char getDelimiter(); public abstract AbstractAttributeKey append(String property); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractPersistentAttributeMemberResolver.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractPersistentAttributeMemberResolver.java index 54e6fac33e..6e980e479e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractPersistentAttributeMemberResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/AbstractPersistentAttributeMemberResolver.java @@ -154,7 +154,7 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi } @SuppressWarnings("RedundantIfStatement") - protected boolean isPersistable(FieldDescriptor fieldDescriptor) { + public static boolean isPersistable(FieldDescriptor fieldDescriptor) { if ( Modifier.isTransient( fieldDescriptor.getModifiers() ) ) { return false; } @@ -188,7 +188,7 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi } @SuppressWarnings("RedundantIfStatement") - protected boolean isPersistable(MethodDescriptor methodDescriptor) { + public static boolean isPersistable(MethodDescriptor methodDescriptor) { if ( !methodDescriptor.getArgumentTypes().isEmpty() ) { return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BaseDelegatingBindingContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BaseDelegatingBindingContext.java index 6e439058b2..091d00bcd1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BaseDelegatingBindingContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BaseDelegatingBindingContext.java @@ -28,6 +28,11 @@ import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptorRepository; import org.hibernate.metamodel.source.internal.annotations.JandexAccess; import org.hibernate.metamodel.source.spi.MappingDefaults; import org.hibernate.metamodel.source.spi.MetaAttributeContext; +import org.hibernate.metamodel.spi.domain.Aggregate; +import org.hibernate.metamodel.spi.domain.BasicType; +import org.hibernate.metamodel.spi.domain.Entity; +import org.hibernate.metamodel.spi.domain.Hierarchical; +import org.hibernate.metamodel.spi.domain.MappedSuperclass; import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.service.ServiceRegistry; @@ -97,6 +102,53 @@ public abstract class BaseDelegatingBindingContext implements BindingContext { return parent.quoteIdentifiersInContext(); } + @Override + public BasicType buildBasicDomainType(JavaTypeDescriptor typeDescriptor) { + return parent().buildBasicDomainType( typeDescriptor ); + } + + @Override + public MappedSuperclass buildMappedSuperclassDomainType(JavaTypeDescriptor typeDescriptor) { + return parent().buildMappedSuperclassDomainType( typeDescriptor ); + } + + @Override + public MappedSuperclass buildMappedSuperclassDomainType( + JavaTypeDescriptor typeDescriptor, Hierarchical superType) { + return parent().buildMappedSuperclassDomainType( typeDescriptor, superType ); + } + + @Override + public Aggregate buildComponentDomainType(JavaTypeDescriptor typeDescriptor) { + return parent().buildComponentDomainType( typeDescriptor ); + } + + @Override + public Aggregate buildComponentDomainType( + JavaTypeDescriptor typeDescriptor, Hierarchical superType) { + return parent().buildComponentDomainType( typeDescriptor, superType ); + } + + @Override + public Entity buildEntityDomainType(JavaTypeDescriptor typeDescriptor) { + return parent().buildEntityDomainType( typeDescriptor ); + } + + @Override + public Entity buildEntityDomainType(JavaTypeDescriptor typeDescriptor, Hierarchical superType) { + return parent().buildEntityDomainType( typeDescriptor, superType ); + } + + @Override + public Type locateDomainType(JavaTypeDescriptor typeDescriptor) { + return parent().locateDomainType( typeDescriptor ); + } + + @Override + public Type locateOrBuildDomainType(JavaTypeDescriptor typeDescriptor, boolean isAggregate) { + return parent().locateOrBuildDomainType( typeDescriptor, isAggregate ); + } + @Override public Type makeDomainType(String className) { return parent.makeDomainType( className ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BindingContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BindingContext.java index 8039e25bd5..a2b9375df6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BindingContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/BindingContext.java @@ -29,7 +29,12 @@ import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptorRepository; import org.hibernate.metamodel.source.internal.annotations.JandexAccess; import org.hibernate.metamodel.source.spi.MappingDefaults; import org.hibernate.metamodel.source.spi.MetaAttributeContext; +import org.hibernate.metamodel.spi.domain.Aggregate; +import org.hibernate.metamodel.spi.domain.BasicType; +import org.hibernate.metamodel.spi.domain.Entity; +import org.hibernate.metamodel.spi.domain.Hierarchical; import org.hibernate.metamodel.spi.domain.JavaClassReference; +import org.hibernate.metamodel.spi.domain.MappedSuperclass; import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.service.ServiceRegistry; @@ -104,6 +109,27 @@ public interface BindingContext { public JavaTypeDescriptor typeDescriptor(String name); + public BasicType buildBasicDomainType(JavaTypeDescriptor typeDescriptor); + public MappedSuperclass buildMappedSuperclassDomainType(JavaTypeDescriptor typeDescriptor); + public MappedSuperclass buildMappedSuperclassDomainType(JavaTypeDescriptor typeDescriptor, Hierarchical superType); + public Aggregate buildComponentDomainType(JavaTypeDescriptor typeDescriptor); + public Aggregate buildComponentDomainType(JavaTypeDescriptor typeDescriptor, Hierarchical superType); + public Entity buildEntityDomainType(JavaTypeDescriptor typeDescriptor); + public Entity buildEntityDomainType(JavaTypeDescriptor typeDescriptor, Hierarchical superType); + + public Type locateDomainType(JavaTypeDescriptor typeDescriptor); + + /** + * It is expected that Entity types already exist and are known. Therefore, + * in the "build" case, the expectation is that the domain type is either + * a basic type or a component. + * + * @param typeDescriptor The Java type descriptor + * + * @return The domain type. + */ + public Type locateOrBuildDomainType(JavaTypeDescriptor typeDescriptor, boolean isAggregate); + // todo : go away /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractAttributeBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractAttributeBindingContainer.java index 3848e15458..45c33f2ccf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractAttributeBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractAttributeBindingContainer.java @@ -93,7 +93,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind return attributeBindingMapInternal().values(); } - protected void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) { + public void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) { for ( AttributeBinding subAttributeBinding : attributeBindings() ) { if ( AbstractSingularAttributeBinding.class.isInstance( subAttributeBinding ) ) { ( (AbstractSingularAttributeBinding) subAttributeBinding ).collectRelationalValueBindings( relationalValueBindingContainer ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractEmbeddableBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractEmbeddableBinding.java index 18f752b13e..62185fbb7b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractEmbeddableBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractEmbeddableBinding.java @@ -46,7 +46,7 @@ import org.hibernate.tuple.component.ComponentTuplizer; */ public abstract class AbstractEmbeddableBinding extends AbstractAttributeBindingContainer - implements EmbeddableBinding { + implements EmbeddableBindingImplementor { private final EntityBinding entityBinding; private final AttributeContainer attributeContainer; private final TableSpecification primaryTable; @@ -116,7 +116,8 @@ public abstract class AbstractEmbeddableBinding protected abstract boolean isModifiable(); - protected RelationalValueBindingContainer getRelationalValueBindingContainer() { + @Override + public RelationalValueBindingContainer getRelationalValueBindingContainer() { final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer(); collectRelationalValueBindings( bindingContainer ); return bindingContainer; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java index 58695cbe13..4fc236e707 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java @@ -42,7 +42,7 @@ public class BasicAttributeBinding private final RelationalValueBindingContainer relationalValueBindingContainer; private final PropertyGeneration generation; - BasicAttributeBinding( + public BasicAttributeBinding( AttributeBindingContainer container, SingularAttribute attribute, List relationalValueBindings, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java index adf3680405..ee827d83c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java @@ -27,6 +27,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.spi.MetaAttributeContext; import org.hibernate.metamodel.spi.PluralAttributeIndexNature; import org.hibernate.metamodel.spi.domain.Aggregate; @@ -54,7 +55,7 @@ public class CompositePluralAttributeIndexBinding extends AbstractPluralAttribut } public EmbeddableBinding createCompositeAttributeBindingContainer( - Aggregate aggregate, + final Aggregate aggregate, MetaAttributeContext metaAttributeContext, SingularAttribute parentReference, Class tuplizerClass) { @@ -83,6 +84,11 @@ public class CompositePluralAttributeIndexBinding extends AbstractPluralAttribut public boolean isAggregated() { return true; } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return aggregate.getDescriptor(); + } }; return compositeAttributeBindingContainer; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBinding.java index 5aa7b15c8f..26a8ce41dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBinding.java @@ -23,6 +23,7 @@ */ package org.hibernate.metamodel.spi.binding; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.spi.domain.SingularAttribute; import org.hibernate.tuple.component.ComponentTuplizer; @@ -33,6 +34,8 @@ public interface EmbeddableBinding extends AttributeBindingContainer { boolean isAggregated(); SingularAttribute getParentReference(); + JavaTypeDescriptor getTypeDescriptor(); + @Override Class getCustomTuplizerClass(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBindingImplementor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBindingImplementor.java new file mode 100644 index 0000000000..d1f4ad56e0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddableBindingImplementor.java @@ -0,0 +1,32 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, 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.metamodel.spi.binding; + +/** + * @author Steve Ebersole + */ +public interface EmbeddableBindingImplementor extends EmbeddableBinding { + public RelationalValueBindingContainer getRelationalValueBindingContainer(); + public void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddedAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddedAttributeBinding.java index 0dbe158c96..c3f344a338 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddedAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EmbeddedAttributeBinding.java @@ -30,6 +30,7 @@ import java.util.Map; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.CascadeStyles; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.spi.MetaAttributeContext; import org.hibernate.metamodel.spi.AttributePath; import org.hibernate.metamodel.spi.AttributeRole; @@ -48,9 +49,9 @@ public class EmbeddedAttributeBinding extends AbstractSingularAttributeBinding implements SingularNonAssociationAttributeBinding, Cascadeable, EmbeddableBindingContributor { - private final AbstractEmbeddableBinding embeddableBinding; + private final EmbeddableBindingImplementor embeddableBinding; - private EmbeddedAttributeBinding( + public EmbeddedAttributeBinding( AttributeBindingContainer container, SingularAttribute attribute, String propertyAccessorName, @@ -60,7 +61,7 @@ public class EmbeddedAttributeBinding MetaAttributeContext metaAttributeContext, AttributeRole attributeRole, AttributePath attributePath, - AbstractEmbeddableBinding embeddableBinding) { + EmbeddableBindingImplementor embeddableBinding) { super( container, attribute, @@ -79,7 +80,7 @@ public class EmbeddedAttributeBinding public static EmbeddedAttributeBinding createEmbeddedAttributeBinding( final AttributeBindingContainer container, - SingularAttribute attribute, + final SingularAttribute attribute, String propertyAccessorName, boolean includedInOptimisticLocking, boolean lazy, @@ -114,6 +115,11 @@ public class EmbeddedAttributeBinding public boolean isAggregated() { return true; } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return attribute.getSingularAttributeType().getDescriptor(); + } }; if ( ! attribute.getSingularAttributeType().isAggregate() ) { @@ -134,61 +140,61 @@ public class EmbeddedAttributeBinding embeddableBinding ); } - - // TODO: Get rid of this when non-aggregated composite IDs is no longer modelled as a EmbeddedAttributeBinding. - public static EmbeddedAttributeBinding createVirtualEmbeddedAttributeBinding( - final AttributeBindingContainer container, - SingularAttribute syntheticAttribute, - NaturalIdMutability naturalIdMutability, - MetaAttributeContext metaAttributeContext, - AttributeRole attributeRole, - AttributePath attributePath, - final List subAttributeBindings) { - AbstractEmbeddableBinding embeddableBinding = new AbstractEmbeddableBinding( - container.seekEntityBinding(), - (AttributeContainer) syntheticAttribute.getSingularAttributeType(), - container.getPrimaryTable(), - attributeRole, - attributePath, - metaAttributeContext, - null, - null) { - private final Map attributeBindingMap = createUnmodifiableAttributeBindingMap( subAttributeBindings ); - - @Override - protected boolean isModifiable() { - return false; - } - - @Override - protected Map attributeBindingMapInternal() { - return this.attributeBindingMap; - } - - @Override - public boolean isAggregated() { - return false; - } - }; - - if ( syntheticAttribute.getSingularAttributeType().isAggregate() ) { - throw new IllegalArgumentException( - "Cannot create a non-aggregated EmbeddableBinding with an aggregate attribute type" - ); - } - return new EmbeddedAttributeBinding( - container, - syntheticAttribute, - "embedded", // TODO: get rid of "magic" string. - false, - false, - naturalIdMutability, - metaAttributeContext, - attributeRole, - attributePath, - embeddableBinding - ); - } +// +// // TODO: Get rid of this when non-aggregated composite IDs is no longer modelled as a EmbeddedAttributeBinding. +// public static EmbeddedAttributeBinding createVirtualEmbeddedAttributeBinding( +// final AttributeBindingContainer container, +// SingularAttribute syntheticAttribute, +// NaturalIdMutability naturalIdMutability, +// MetaAttributeContext metaAttributeContext, +// AttributeRole attributeRole, +// AttributePath attributePath, +// final List subAttributeBindings) { +// AbstractEmbeddableBinding embeddableBinding = new AbstractEmbeddableBinding( +// container.seekEntityBinding(), +// (AttributeContainer) syntheticAttribute.getSingularAttributeType(), +// container.getPrimaryTable(), +// attributeRole, +// attributePath, +// metaAttributeContext, +// null, +// null) { +// private final Map attributeBindingMap = createUnmodifiableAttributeBindingMap( subAttributeBindings ); +// +// @Override +// protected boolean isModifiable() { +// return false; +// } +// +// @Override +// protected Map attributeBindingMapInternal() { +// return this.attributeBindingMap; +// } +// +// @Override +// public boolean isAggregated() { +// return false; +// } +// }; +// +// if ( syntheticAttribute.getSingularAttributeType().isAggregate() ) { +// throw new IllegalArgumentException( +// "Cannot create a non-aggregated EmbeddableBinding with an aggregate attribute type" +// ); +// } +// return new EmbeddedAttributeBinding( +// container, +// syntheticAttribute, +// "embedded", // TODO: get rid of "magic" string. +// false, +// false, +// naturalIdMutability, +// metaAttributeContext, +// attributeRole, +// attributePath, +// embeddableBinding +// ); +// } private static Map createUnmodifiableAttributeBindingMap( List subAttributeBindings) { 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 ad98b4c40b..3d451a0938 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 @@ -32,6 +32,7 @@ import java.util.Map; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.FilterConfiguration; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.ArrayHelper; @@ -228,11 +229,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements TableSpecification table, List values, boolean searchParent) { - SingularAttributeBinding attributeBinding = null; - SingularAttributeBinding idAttributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding(); - if ( primaryTable.equals( table ) && idAttributeBinding.getValues().equals( values ) ) { - attributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding(); - } + SingularAttributeBinding attributeBinding = locateAttributeBindingFromIdentifier( table, values ); if ( attributeBinding == null ) { attributeBinding = locateAttributeBinding( table, values ); } @@ -242,6 +239,28 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements return attributeBinding; } + private SingularAttributeBinding locateAttributeBindingFromIdentifier( + TableSpecification table, + List values) { + if ( !primaryTable.equals( table ) ) { + return null; + } + + final EntityIdentifier idInfo = hierarchyDetails.getEntityIdentifier(); + final SingularAttributeBinding idAttributeBinding = idInfo.getEntityIdentifierBinding().getAttributeBinding(); + final List idAttributeValues = idAttributeBinding.getValues(); + // order-insensitive check (column order handled later) + if ( idAttributeValues.size() == values.size() + && idAttributeValues.containsAll( values ) ) { + return idAttributeBinding; + } +// if ( idAttributeValues.equals( values ) ) { +// return idAttributeBinding; +// } + + return null; + } + public AttributeBinding locateAttributeBindingByPath(String path, boolean searchParent) { if ( path == null ) { throw new IllegalArgumentException( "path must be non-null." ); @@ -519,27 +538,29 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements ); } + public EmbeddedAttributeBinding makeVirtualCompositeAttributeBinding( SingularAttribute syntheticAttribute, - MetaAttributeContext metaAttributeContext, - List idAttributeBindings) { + EmbeddableBindingImplementor virtualEmbeddableBinding, + MetaAttributeContext metaAttributeContext) { if ( !syntheticAttribute.isSynthetic() ) { throw new AssertionFailure( "Illegal attempt to create synthetic attribute binding from non-synthetic attribute reference" ); } - // TODO: make sure all attributes are singular - final EmbeddedAttributeBinding binding = EmbeddedAttributeBinding.createVirtualEmbeddedAttributeBinding( + + return new EmbeddedAttributeBinding( this, syntheticAttribute, + "embedded", // TODO: get rid of "magic" string. + false, + false, NaturalIdMutability.NOT_NATURAL_ID, metaAttributeContext, getRoleBase(), getPathBase(), - idAttributeBindings + virtualEmbeddableBinding ); -// registerAttributeBinding( binding ); - return binding; } public BackRefAttributeBinding makeBackRefAttributeBinding( @@ -664,7 +685,9 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements public List getNonIdAttributeBindings() { final List list = new ArrayList(); for ( final AttributeBinding ab : attributeBindings() ) { - boolean isId = getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( ab ); + boolean isId = getHierarchyDetails().getEntityIdentifier() + .getEntityIdentifierBinding() + .isIdentifierAttributeBinding( ab ); if ( !isId ) { list.add( ab ); } @@ -813,8 +836,10 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements private List keyRelationalValueBindings; public List getKeyRelationalValueBindings() { - if(keyRelationalValueBindings == null){ - keyRelationalValueBindings = getHierarchyDetails().getEntityIdentifier().getAttributeBinding().getRelationalValueBindings(); + if ( keyRelationalValueBindings == null ) { + keyRelationalValueBindings = getHierarchyDetails().getEntityIdentifier() + .getEntityIdentifierBinding() + .getRelationalValueBindings(); } return keyRelationalValueBindings; } @@ -837,5 +862,4 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements } return 0; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityIdentifier.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityIdentifier.java index e1cebfc67a..dedd913f0a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityIdentifier.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityIdentifier.java @@ -25,10 +25,10 @@ package org.hibernate.metamodel.spi.binding; import java.io.Serializable; import java.util.List; -import java.util.Map; +import java.util.Locale; import java.util.Properties; -import org.hibernate.MappingException; +import org.hibernate.AnnotationException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.id.CompositeNestedGeneratedValueGenerator; @@ -37,11 +37,15 @@ import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.TableSpecification; -import org.hibernate.property.Setter; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tuple.component.ComponentMetamodel; +import org.hibernate.type.Type; +import org.hibernate.type.TypeFactory; import static org.hibernate.id.EntityIdentifierNature.AGGREGATED_COMPOSITE; import static org.hibernate.id.EntityIdentifierNature.NON_AGGREGATED_COMPOSITE; @@ -58,6 +62,19 @@ import static org.hibernate.id.EntityIdentifierNature.SIMPLE; * multi-attribute identifier - non-aggregated composite identifiers *

  2. * + *

    + * The EntityIdentifier instance is created when the entity hierarchy is, but at + * that time we do not know all the information needed for interpreting the nature + * of the identifier. So at some point after creation, one of the prepare methods + * must be called:

      + *
    • {@link #prepareAsSimpleIdentifier}
    • + *
    • {@link #prepareAsAggregatedCompositeIdentifier}
    • + *
    • {@link #prepareAsNonAggregatedCompositeIdentifier}
    • + *
    + * Attempts to prepare the EntityIdentifier more than once will result in an + * exception. Attempts to access the information contained in the + * EntityIdentifier prior to binding will (generally) result in an + * exception. * * @author Steve Ebersole * @author Hardy Ferentschik @@ -66,8 +83,7 @@ import static org.hibernate.id.EntityIdentifierNature.SIMPLE; public class EntityIdentifier { private final EntityBinding entityBinding; - private Binding binding; - private LookupClassBinding lookupClassBinding; + private BindingImplementor identifierBinding; private IdentifierGenerator identifierGenerator; @@ -84,129 +100,158 @@ public class EntityIdentifier { return entityBinding; } - public void prepareAsSimpleIdentifier( + public SimpleIdentifierBinding prepareAsSimpleIdentifier( SingularAttributeBinding attributeBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, - String unsavedValue, - Class lookupIdClass, - String lookupIdClassAccessType) { + String unsavedValue) { ensureNotBound(); - this.entityIdentifierBinding = new SimpleAttributeIdentifierBindingImpl( + this.identifierBinding = new SimpleIdentifierBindingImpl( + this.getEntityBinding(), attributeBinding, identifierGeneratorDefinition, unsavedValue ); - this.lookupClassBinding = new LookupClassBindingImpl( lookupIdClass, lookupIdClassAccessType ); + return (SimpleIdentifierBinding) identifierBinding; } - public void prepareAsAggregatedCompositeIdentifier( + public AggregatedCompositeIdentifierBinding prepareAsAggregatedCompositeIdentifier( EmbeddedAttributeBinding attributeBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, - String unsavedValue, - Class lookupIdClass, - String lookupIdClassAccessType) { + String unsavedValue) { ensureNotBound(); - this.entityIdentifierBinding = new AggregatedComponentIdentifierBindingImpl( + this.identifierBinding = new AggregatedCompositeIdentifierBindingImpl( + this.getEntityBinding(), attributeBinding, identifierGeneratorDefinition, unsavedValue ); - this.lookupClassBinding = new LookupClassBindingImpl( lookupIdClass, lookupIdClassAccessType ); + return (AggregatedCompositeIdentifierBinding) identifierBinding; } - public void prepareAsNonAggregatedCompositeIdentifier( - EmbeddedAttributeBinding embeddedAttributeBinding, + public NonAggregatedCompositeIdentifierBinding prepareAsNonAggregatedCompositeIdentifier( + EmbeddableBindingImplementor virtualEmbeddableBinding, + EmbeddedAttributeBinding virtualAttributeBinding, + EmbeddableBindingImplementor idClassEmbeddableBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, - String unsavedValue, - Class lookupIdClass, - String lookupIdClassAccessType) { + String unsavedValue) { ensureNotBound(); - this.entityIdentifierBinding = new NonAggregatedCompositeIdentifierBindingImpl( - embeddedAttributeBinding, + this.identifierBinding = new NonAggregatedCompositeIdentifierBindingImpl( + this.getEntityBinding(), + virtualEmbeddableBinding, + virtualAttributeBinding, + idClassEmbeddableBinding, identifierGeneratorDefinition, - unsavedValue, - lookupIdClass, - lookupIdClassAccessType + unsavedValue ); - this.lookupClassBinding = new LookupClassBindingImpl( lookupIdClass, lookupIdClassAccessType ); + + return (NonAggregatedCompositeIdentifierBinding) identifierBinding; } - public EntityIdentifierBinding getEntityIdentifierBinding() { - return entityIdentifierBinding; - } - - public LookupClassBinding getLookupClassBinding() { - return lookupClassBinding; - } public EntityIdentifierNature getNature() { ensureBound(); - return binding.getNature(); + return identifierBinding.getNature(); } - public SingularAttributeBinding getAttributeBinding() { + public Binding getEntityIdentifierBinding() { ensureBound(); - return entityIdentifierBinding.getAttributeBinding(); + return identifierBinding; } - public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding) { + public boolean definesIdClass() { ensureBound(); - return entityIdentifierBinding.isIdentifierAttributeBinding( attributeBinding ); + return getNature() == NON_AGGREGATED_COMPOSITE + && ( (NonAggregatedCompositeIdentifierBinding) identifierBinding ).getIdClassMetadata() != null; } - public boolean isCascadeDeleteEnabled() { - if ( getAttributeBinding() instanceof Cascadeable ) { - Cascadeable cascadeable = Cascadeable.class.cast( getAttributeBinding() ); - cascadeable.getCascadeStyle();//todo - } - return false; - } - - public String getUnsavedValue() { - ensureBound(); - return binding.getUnsavedValue(); - } - - public boolean isNonAggregatedComposite() { - ensureBound(); - return getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE; - } - - /** - * Get the Class of the {@link javax.persistence.IdClass} associated with the entity, if one. - * - * @deprecated Use {@link #getLookupClassBinding()} instead - */ - @Deprecated - public Class getIdClassClass() { - ensureBound(); - return getLookupClassBinding().getIdClassType(); - } - - /** - * @deprecated Use {@link #getLookupClassBinding()} instead - */ - @Deprecated - public String getIdClassPropertyAccessorName() { - ensureBound(); - return getLookupClassBinding().getAccessStrategy(); - } - - /** - * @deprecated Use {@link #getLookupClassBinding()} instead - */ - @Deprecated - public boolean isIdentifierMapper() { - ensureBound(); - return isNonAggregatedComposite() && getLookupClassBinding().getIdClassType() != null; - } +// public IdClassMetadata getIdClassMetadata() { +// return idClassMetadata; +// } +// +// +// /** +// * @deprecated Use the {@link #getEntityIdentifierBinding} instead +// */ +// @Deprecated +// public SingularAttributeBinding getAttributeBinding() { +// ensureBound(); +// return identifierBinding.getAttributeBinding(); +// } +// +// /** +// * @deprecated Use the {@link #getEntityIdentifierBinding} instead +// */ +// @Deprecated +// public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding) { +// ensureBound(); +// return identifierBinding.isIdentifierAttributeBinding( attributeBinding ); +// } +// +// /** +// * @deprecated No real replacement; not even used atm +// */ +// @Deprecated +// public boolean isCascadeDeleteEnabled() { +// if ( getAttributeBinding() instanceof Cascadeable ) { +// Cascadeable cascadeable = Cascadeable.class.cast( getAttributeBinding() ); +// cascadeable.getCascadeStyle();//todo +// } +// return false; +// } +// +// /** +// * @deprecated Use the {@link #getEntityIdentifierBinding} instead +// */ +// @Deprecated +// public String getUnsavedValue() { +// ensureBound(); +// return identifierBinding.getUnsavedValue(); +// } +// +// /** +// * @deprecated Check nature +// */ +// @Deprecated +// public boolean isNonAggregatedComposite() { +// ensureBound(); +// return getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE; +// } +// +// /** +// * Get the Class of the {@link javax.persistence.IdClass} associated with the entity, if one. +// * +// * @deprecated Use {@link #getIdClassMetadata()} instead +// */ +// @Deprecated +// public JavaTypeDescriptor getIdClassClass() { +// ensureBound(); +// return getIdClassMetadata().getIdClassType(); +// } +// +// /** +// * @deprecated Use {@link #getIdClassMetadata()} instead +// */ +// @Deprecated +// public String getIdClassPropertyAccessorName() { +// ensureBound(); +// return null; +// } +// +// /** +// * @deprecated Use {@link #getIdClassMetadata()} instead +// */ +// @Deprecated +// public boolean isIdentifierMapper() { +// ensureBound(); +// return isNonAggregatedComposite() && getIdClassMetadata().getIdClassType() != null; +// } // todo do we really need this createIdentifierGenerator and how do we make sure the getter is not called too early // maybe some sort of visitor pattern here!? (HF) public IdentifierGenerator createIdentifierGenerator(IdentifierGeneratorFactory factory, Properties properties) { ensureBound(); if ( identifierGenerator == null ) { - identifierGenerator = entityIdentifierBinding.createIdentifierGenerator( factory, properties ); + identifierGenerator = identifierBinding.createIdentifierGenerator( factory, properties ); } return identifierGenerator; } @@ -228,117 +273,218 @@ public class EntityIdentifier { } } - protected boolean isBound() { - return entityIdentifierBinding != null; + public boolean isBound() { + return identifierBinding != null; } - public int getColumnCount() { - ensureBound(); - return entityIdentifierBinding.getColumnCount(); - } /** - * For now simply models {@link javax.persistence.IdClass} information. Ultimately should - * handle {@link javax.persistence.MapsId} information as well. + * @deprecated Use {@link #getEntityIdentifierBinding()} instead */ - public static interface LookupClassBinding { - public boolean definedIdClass(); - public Class getIdClassType(); - public String getAccessStrategy(); + @Deprecated + public int getColumnCount() { + ensureBound(); + return identifierBinding.getColumnCount(); } - private static class LookupClassBindingImpl implements LookupClassBinding { - private final Class idClassType; - private final String accessStrategy; + // todo : expose IdClassMetadata just from NonAggregatedCompositeIdentifierBindingImpl ? + // - that is the only place it has relevance - private LookupClassBindingImpl(Class idClassType, String accessStrategy) { - this.idClassType = idClassType; - this.accessStrategy = idClassType == null ? null : accessStrategy; + /** + * Models {@link javax.persistence.IdClass} information. + */ + public static interface IdClassMetadata { + public EmbeddableBinding getEmbeddableBinding(); + public JavaTypeDescriptor getIdClassType(); + public String getAccessStrategy(String attributeName); + public Type getHibernateType(ServiceRegistry serviceRegistry, TypeFactory typeFactory); + } + + private static class IdClassMetadataImpl implements IdClassMetadata { + private final EmbeddableBinding idClassBinding; + + private Type type; + + private IdClassMetadataImpl(EmbeddableBinding idClassBinding) { + this.idClassBinding = idClassBinding; } @Override - public boolean definedIdClass() { - return getIdClassType() != null; + public EmbeddableBinding getEmbeddableBinding() { + return idClassBinding; } @Override - public Class getIdClassType() { - return idClassType; + public JavaTypeDescriptor getIdClassType() { + return idClassBinding.getTypeDescriptor(); } @Override - public String getAccessStrategy() { - return accessStrategy; + public String getAccessStrategy(String attributeName) { + final AttributeBinding attributeBinding = idClassBinding.locateAttributeBinding( attributeName ); + if ( attributeBinding == null ) { + throw new AnnotationException( + String.format( + Locale.ENGLISH, + "Unable to locate IdClass attribute by that name : %s, %s", + getIdClassType().getName().toString(), + attributeName + ) + ); + } + + return attributeBinding.getPropertyAccessorName(); + } + + @Override + public Type getHibernateType(ServiceRegistry serviceRegistry, TypeFactory typeFactory) { + if ( type == null && idClassBinding != null ) { + type = typeFactory.embeddedComponent( + new ComponentMetamodel( serviceRegistry, idClassBinding, true, false ) + ); + } + return type; } } - private abstract class EntityIdentifierBinding { - private final EntityIdentifierNature nature; - private final SingularAttributeBinding identifierAttributeBinding; + public static interface Binding { + public EntityIdentifierNature getNature(); + public SingularAttributeBinding getAttributeBinding(); + public String getUnsavedValue(); + public List getRelationalValueBindings(); + public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding); + public Type getHibernateType(); + } + + public static interface AttributeBasedIdentifierBinding extends Binding { + } + + public static interface SimpleIdentifierBinding extends AttributeBasedIdentifierBinding { + } + + public static interface AggregatedCompositeIdentifierBinding extends AttributeBasedIdentifierBinding { + @Override + public EmbeddedAttributeBinding getAttributeBinding(); + } + + public static interface NonAggregatedCompositeIdentifierBinding extends Binding { + /** + * Obtain the virtual Embeddable representation of the identifier. This + * maps to the entity class, but handles just the id attributes. + * + * @return The virtual Embeddable binding + */ + public EmbeddableBinding getVirtualEmbeddableBinding(); + + /** + * Obtain metadata about the IdClass, if one. + * + * @return Metadata about the defined IdClass, or {@code null} if + * no IdClass was defined. + */ + public IdClassMetadata getIdClassMetadata(); + + /** + * Builds the Type for the "virtual embeddable". See + * {@link IdClassMetadata#getHibernateType} for obtaining the Type + * relating to the IdClass + * + * Caches the Type reference after first call. + * + * @param serviceRegistry The ServiceRegistry + * @param typeFactory The TypeFactory + * + * @return The resolved Type + */ + public Type getHibernateType(ServiceRegistry serviceRegistry, TypeFactory typeFactory); + } + + private static interface BindingImplementor extends Binding { + public int getColumnCount(); + public IdentifierGenerator createIdentifierGenerator( + IdentifierGeneratorFactory identifierGeneratorFactory, + Properties properties); + } + + private static abstract class AbstractIdentifierBinding implements BindingImplementor { + private final EntityBinding entityBinding; private final IdentifierGeneratorDefinition identifierGeneratorDefinition; private final String unsavedValue; + + protected AbstractIdentifierBinding( + EntityBinding entityBinding, + IdentifierGeneratorDefinition identifierGeneratorDefinition, + String unsavedValue) { + this.entityBinding = entityBinding; + this.identifierGeneratorDefinition = identifierGeneratorDefinition; + this.unsavedValue = unsavedValue; + } + + public EntityBinding getEntityBinding() { + return entityBinding; + } + + @Override + public String getUnsavedValue() { + return unsavedValue; + } + + public IdentifierGeneratorDefinition getGeneratorDefinition() { + return identifierGeneratorDefinition; + } + } + + private static abstract class AbstractAttributeBasedIdentifierBinding + extends AbstractIdentifierBinding + implements AttributeBasedIdentifierBinding { + private final SingularAttributeBinding identifierAttributeBinding; private final int columnCount; - protected EntityIdentifierBinding( - EntityIdentifierNature nature, + protected AbstractAttributeBasedIdentifierBinding( + EntityBinding entityBinding, SingularAttributeBinding identifierAttributeBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, String unsavedValue) { - this.nature = nature; + super( entityBinding, identifierGeneratorDefinition, unsavedValue ); this.identifierAttributeBinding = identifierAttributeBinding; - this.identifierGeneratorDefinition = identifierGeneratorDefinition; - this.unsavedValue = unsavedValue; // Configure primary key in relational model final List relationalValueBindings = identifierAttributeBinding.getRelationalValueBindings(); this.columnCount = relationalValueBindings.size(); for ( final RelationalValueBinding valueBinding : relationalValueBindings ) { - entityBinding.getPrimaryTable().getPrimaryKey().addColumn( (Column) valueBinding.getValue() ); + entityBinding.getPrimaryTable() + .getPrimaryKey() + .addColumn( (Column) valueBinding.getValue() ); } } - public EntityIdentifierNature getNature() { - return nature; - } - + @Override public SingularAttributeBinding getAttributeBinding() { return identifierAttributeBinding; } - public String getUnsavedValue() { - return unsavedValue; - } - - protected IdentifierGeneratorDefinition getIdentifierGeneratorDefinition() { - return identifierGeneratorDefinition; - } - + @Override public int getColumnCount() { return columnCount; } + @Override + public List getRelationalValueBindings() { + return getAttributeBinding().getRelationalValueBindings(); + } + + @Override public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding) { return getAttributeBinding().equals( attributeBinding ); } + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory identifierGeneratorFactory, Properties properties) { - final List relationalValueBindings = - getAttributeBinding().getRelationalValueBindings(); - // TODO: If multiple @Column annotations exist within an id's - // @Columns, we need a more solid solution than simply grabbing - // the first one to get the TableSpecification. - - final RelationalValueBinding relationalValueBinding = relationalValueBindings.get( 0 ); - final TableSpecification table = relationalValueBinding.getTable(); - if ( !Column.class.isInstance( relationalValueBinding.getValue() ) ) { - throw new MappingException( - "Cannot create an IdentifierGenerator because the value is not a column: " + - relationalValueBinding.getValue().toLoggableString() - ); - } + final List valueBindings = getAttributeBinding().getRelationalValueBindings(); + final TableSpecification table = getEntityBinding().getPrimaryTable(); Properties params = new Properties(); params.putAll( properties ); @@ -356,8 +502,8 @@ public class EntityIdentifier { } } - params.setProperty( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntityName() ); - params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, entityBinding.getJpaEntityName() ); + params.setProperty( IdentifierGenerator.ENTITY_NAME, getEntityBinding().getEntityName() ); + params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, getEntityBinding().getJpaEntityName() ); //init the table here instead of earlier, so that we can get a quoted table name //TODO: would it be better to simply pass the qualified table name, instead of @@ -365,73 +511,94 @@ public class EntityIdentifier { String tableName = table.getQualifiedName( identifierGeneratorFactory.getDialect() ); params.setProperty( PersistentIdentifierGenerator.TABLE, tableName ); - params.setProperty( - PersistentIdentifierGenerator.PK, - ( (Column) relationalValueBinding.getValue() ).getColumnName().getText( - identifierGeneratorFactory.getDialect() - ) - ); - if ( entityBinding.getHierarchyDetails().getInheritanceType() != InheritanceType.TABLE_PER_CLASS ) { + if ( valueBindings.size() == 1 ) { + final RelationalValueBinding rvBinding = valueBindings.get( 0 ); + if ( Column.class.isInstance( rvBinding.getValue() ) ) { + final Column pkColumn = (Column) rvBinding.getValue(); + params.setProperty( + PersistentIdentifierGenerator.PK, + pkColumn.getColumnName().getText( identifierGeneratorFactory.getDialect() ) + ); + } + } + + if ( getEntityBinding().getHierarchyDetails().getInheritanceType() != InheritanceType.TABLE_PER_CLASS ) { params.setProperty( PersistentIdentifierGenerator.TABLES, tableName ); - } else { + } + else { params.setProperty( PersistentIdentifierGenerator.TABLES, - resolveTableNames( identifierGeneratorFactory.getDialect(), entityBinding ) + resolveTableNames( identifierGeneratorFactory.getDialect(), getEntityBinding() ) ); } - params.putAll( getIdentifierGeneratorDefinition().getParameters() ); + params.putAll( getGeneratorDefinition().getParameters() ); return identifierGeneratorFactory.createIdentifierGenerator( - getIdentifierGeneratorDefinition().getStrategy(), + getGeneratorDefinition().getStrategy(), getAttributeBinding().getHibernateTypeDescriptor().getResolvedTypeMapping(), params ); } + + private String resolveTableNames(Dialect dialect, EntityBinding entityBinding) { + EntityBinding[] ebs = entityBinding.getPostOrderSubEntityBindingClosure(); + StringBuilder tableNames = new StringBuilder(); + String tbName = resolveTableName( dialect, entityBinding ); + if( StringHelper.isNotEmpty( tbName )){ + tableNames.append( tbName ); + } + + for ( EntityBinding eb : ebs ) { + tbName = resolveTableName( dialect, eb ); + if(StringHelper.isNotEmpty( tbName )){ + tableNames.append( ", " ).append( tbName ); + } + } + return tableNames.toString(); + } + + private String resolveTableName(Dialect dialect, EntityBinding entityBinding) { + TableSpecification tableSpecification = entityBinding.getPrimaryTable(); + if ( tableSpecification instanceof Table ) { + Table tb = (Table) tableSpecification; + if ( tb.isPhysicalTable() ) { + return tb.getTableName().toText( dialect ); + } + } + return null; + } + + @Override + public Type getHibernateType() { + return getAttributeBinding().getHibernateTypeDescriptor().getResolvedTypeMapping(); + } } - private class SimpleAttributeIdentifierBindingImpl extends EntityIdentifierBinding { - SimpleAttributeIdentifierBindingImpl( + private class SimpleIdentifierBindingImpl + extends AbstractAttributeBasedIdentifierBinding + implements SimpleIdentifierBinding { + SimpleIdentifierBindingImpl( + EntityBinding entityBinding, SingularAttributeBinding identifierAttributeBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, String unsavedValue) { - super( SIMPLE, identifierAttributeBinding, identifierGeneratorDefinition, unsavedValue ); + super( entityBinding, identifierAttributeBinding, identifierGeneratorDefinition, unsavedValue ); } + @Override + public EntityIdentifierNature getNature() { + return SIMPLE; + } } - private String resolveTableNames(Dialect dialect, EntityBinding entityBinding) { - EntityBinding[] ebs = entityBinding.getPostOrderSubEntityBindingClosure(); - StringBuilder tableNames = new StringBuilder(); - String tbName = resolveTableName( dialect, entityBinding ); - if( StringHelper.isNotEmpty( tbName )){ - tableNames.append( tbName ); - } - - for ( EntityBinding eb : ebs ) { - tbName = resolveTableName( dialect, eb ); - if(StringHelper.isNotEmpty( tbName )){ - tableNames.append( ", " ).append( tbName ); - } - } - return tableNames.toString(); - } - - private String resolveTableName(Dialect dialect, EntityBinding entityBinding) { - TableSpecification tableSpecification = entityBinding.getPrimaryTable(); - if ( tableSpecification instanceof Table ) { - Table tb = (Table) tableSpecification; - if ( tb.isPhysicalTable() ) { - return tb.getTableName().toText( dialect ); - } - } - return null; - } - - private class AggregatedComponentIdentifierBindingImpl extends EntityIdentifierBinding { - AggregatedComponentIdentifierBindingImpl( + private class AggregatedCompositeIdentifierBindingImpl + extends AbstractAttributeBasedIdentifierBinding + implements AggregatedCompositeIdentifierBinding { + AggregatedCompositeIdentifierBindingImpl( + EntityBinding entityBinding, EmbeddedAttributeBinding identifierAttributeBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, String unsavedValue) { - super( AGGREGATED_COMPOSITE, identifierAttributeBinding, identifierGeneratorDefinition, unsavedValue ); + super( entityBinding, identifierAttributeBinding, identifierGeneratorDefinition, unsavedValue ); if ( ! identifierAttributeBinding.getEmbeddableBinding().isAggregated() ) { throw new IllegalArgumentException( String.format( @@ -442,20 +609,31 @@ public class EntityIdentifier { } } + @Override + public EntityIdentifierNature getNature() { + return AGGREGATED_COMPOSITE; + } + + @Override + public EmbeddedAttributeBinding getAttributeBinding() { + return (EmbeddedAttributeBinding) super.getAttributeBinding(); + } + + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory factory, Properties properties) { if ( entityBinding.getSuperEntityBinding() != null ) { throw new AssertionError( "Creating an identifier generator for a component on a subclass." ); } - final EntityIdentifier entityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier(); - final boolean hasCustomGenerator = ! "assigned".equals( getIdentifierGeneratorDefinition().getStrategy() ); + final boolean hasCustomGenerator = ! "assigned".equals( getGeneratorDefinition().getStrategy() ); if ( hasCustomGenerator ) { return super.createIdentifierGenerator( factory, properties ); } + // IMPL NOTE : See the javadoc discussion on CompositeNestedGeneratedValueGenerator wrt the // various scenarios for which we need to account here // we have the "@EmbeddedId" / case @@ -471,98 +649,83 @@ public class EntityIdentifier { } } - private static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan { - private final String propertyName; - private final IdentifierGenerator subGenerator; - private final Setter injector; + private class NonAggregatedCompositeIdentifierBindingImpl + extends AbstractIdentifierBinding + implements NonAggregatedCompositeIdentifierBinding { + private final EmbeddableBindingImplementor virtualEmbeddableBinding; + private final EmbeddedAttributeBinding virtualAttributeBinding; - public ValueGenerationPlan( - String propertyName, - IdentifierGenerator subGenerator, - Setter injector) { - this.propertyName = propertyName; - this.subGenerator = subGenerator; - this.injector = injector; - } + private final IdClassMetadata idClassMetadata; - /** - * {@inheritDoc} - */ - public void execute(SessionImplementor session, Object incomingObject, Object injectionContext) { - final Object generatedValue = subGenerator.generate( session, incomingObject ); - injector.set( injectionContext, generatedValue, session.getFactory() ); - } + private Type type; - public void registerPersistentGenerators(Map generatorMap) { - if ( PersistentIdentifierGenerator.class.isInstance( subGenerator ) ) { - generatorMap.put( ( (PersistentIdentifierGenerator) subGenerator ).generatorKey(), subGenerator ); - } - } - } - - private class NonAggregatedCompositeIdentifierBindingImpl extends EntityIdentifierBinding { - private final Class externalAggregatingClass; - private final String externalAggregatingPropertyAccessorName; - - NonAggregatedCompositeIdentifierBindingImpl( - EmbeddedAttributeBinding identifierAttributeBinding, + public NonAggregatedCompositeIdentifierBindingImpl( + EntityBinding entityBinding, + EmbeddableBindingImplementor virtualEmbeddableBinding, + EmbeddedAttributeBinding virtualAttributeBinding, + EmbeddableBindingImplementor idClassEmbeddableBinding, IdentifierGeneratorDefinition identifierGeneratorDefinition, - String unsavedValue, - Class externalAggregatingClass, - String externalAggregatingPropertyAccessorName) { - super( NON_AGGREGATED_COMPOSITE, identifierAttributeBinding, identifierGeneratorDefinition, unsavedValue ); - if ( identifierAttributeBinding.getEmbeddableBinding().isAggregated() ) { - throw new IllegalArgumentException( - String.format( - "identifierAttributeBinding must be a non-aggregated EmbeddedAttributeBinding: %s", - identifierAttributeBinding.getAttribute().getName() - ) - ); - } - this.externalAggregatingClass = externalAggregatingClass; - this.externalAggregatingPropertyAccessorName = externalAggregatingPropertyAccessorName; - if ( identifierAttributeBinding.getEmbeddableBinding().attributeBindingSpan() == 0 ) { - throw new MappingException( - "A composite ID has 0 attributes for " + entityBinding.getEntityName() - ); - } - for ( AttributeBinding attributeBinding : identifierAttributeBinding.getEmbeddableBinding().attributeBindings() ) { - if ( ! attributeBinding.getAttribute().isSingular() ) { - throw new MappingException( - String.format( - "The composite ID for [%s] contains an attribute [%s} that is plural.", - entityBinding.getEntityName(), - attributeBinding.getAttribute().getName() - ) - ); - } + String unsavedValue) { + super( entityBinding, identifierGeneratorDefinition, unsavedValue ); + this.virtualEmbeddableBinding = virtualEmbeddableBinding; + this.virtualAttributeBinding = virtualAttributeBinding; + this.idClassMetadata = idClassEmbeddableBinding == null + ? null + : new IdClassMetadataImpl( idClassEmbeddableBinding ); + + final List relationalValueBindings = virtualAttributeBinding.getRelationalValueBindings(); + for ( final RelationalValueBinding valueBinding : relationalValueBindings ) { + entityBinding.getPrimaryTable() + .getPrimaryKey() + .addColumn( (Column) valueBinding.getValue() ); } } - private EmbeddedAttributeBinding getNonAggregatedCompositeAttributeBinding() { - return (EmbeddedAttributeBinding) getAttributeBinding(); + @Override + public EntityIdentifierNature getNature() { + return NON_AGGREGATED_COMPOSITE; } + + @Override + public EmbeddableBinding getVirtualEmbeddableBinding() { + return virtualEmbeddableBinding; + } + + @Override + public SingularAttributeBinding getAttributeBinding() { + return virtualAttributeBinding; + } + + @Override + public IdClassMetadata getIdClassMetadata() { + return idClassMetadata; + } + + @Override + public List getRelationalValueBindings() { + return virtualAttributeBinding.getRelationalValueBindings(); + } + + @Override + public int getColumnCount() { + return getRelationalValueBindings().size(); + } + + @Override public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding) { - if ( !isIdentifierMapper() && getNonAggregatedCompositeAttributeBinding().equals( attributeBinding ) ) { + if ( virtualAttributeBinding.equals( attributeBinding ) ) { return true; } - for ( AttributeBinding idAttributeBindings : getNonAggregatedCompositeAttributeBinding().getEmbeddableBinding().attributeBindings() ) { - if ( idAttributeBindings.equals( attributeBinding ) ) { + for ( AttributeBinding embAttrBinding : virtualEmbeddableBinding.attributeBindings() ) { + if ( embAttrBinding.equals( attributeBinding ) ) { return true; } } return false; } - public Class getIdClassClass() { - return externalAggregatingClass; - } - - public String getIdClassPropertyAccessorName() { - return externalAggregatingPropertyAccessorName; - } - + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory factory, Properties properties) { @@ -589,14 +752,56 @@ public class EntityIdentifier { // TODO: set up IdentifierGenerator for non-assigned sub-attributes return new CompositeNestedGeneratedValueGenerator( locator ); } + + @Override + public Type getHibernateType(ServiceRegistry serviceRegistry, TypeFactory typeFactory) { + if ( type == null ) { + type = typeFactory.embeddedComponent( + new ComponentMetamodel( + serviceRegistry, + virtualEmbeddableBinding, + true, + false + ) + ); + } + return type; + } + + @Override + public Type getHibernateType() { + return type; + } } - public static interface Binding { - public EntityIdentifierNature getNature(); - public String getUnsavedValue(); - - public IdentifierGeneratorDefinition getGeneratorDefinition(); - } +// private static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan { +// private final String propertyName; +// private final IdentifierGenerator subGenerator; +// private final Setter injector; +// +// public ValueGenerationPlan( +// String propertyName, +// IdentifierGenerator subGenerator, +// Setter injector) { +// this.propertyName = propertyName; +// this.subGenerator = subGenerator; +// this.injector = injector; +// } +// +// /** +// * {@inheritDoc} +// */ +// public void execute(SessionImplementor session, Object incomingObject, Object injectionContext) { +// final Object generatedValue = subGenerator.generate( session, incomingObject ); +// injector.set( injectionContext, generatedValue, session.getFactory() ); +// } +// +// public void registerPersistentGenerators(Map generatorMap) { +// if ( PersistentIdentifierGenerator.class.isInstance( subGenerator ) ) { +// generatorMap.put( ( (PersistentIdentifierGenerator) subGenerator ).generatorKey(), subGenerator ); +// } +// } +// } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/HibernateTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/HibernateTypeDescriptor.java index fb4ef5a383..55da267d24 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/HibernateTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/HibernateTypeDescriptor.java @@ -23,7 +23,9 @@ */ package org.hibernate.metamodel.spi.binding; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; @@ -41,6 +43,8 @@ public class HibernateTypeDescriptor { private Type resolvedTypeMapping; private JavaTypeDescriptor typeDescriptor; + private List resolutionListeners; + public String getExplicitTypeName() { return explicitTypeName; } @@ -71,6 +75,10 @@ public class HibernateTypeDescriptor { public void setResolvedTypeMapping(Type resolvedTypeMapping) { this.resolvedTypeMapping = resolvedTypeMapping; + + if ( this.resolvedTypeMapping != null ) { + notifyResolutionListeners(); + } } public void copyFrom(HibernateTypeDescriptor hibernateTypeDescriptor) { @@ -79,4 +87,25 @@ public class HibernateTypeDescriptor { getTypeParameters().putAll( hibernateTypeDescriptor.getTypeParameters() ); setResolvedTypeMapping( hibernateTypeDescriptor.getResolvedTypeMapping() ); } + + public static interface ResolutionListener { + public void typeResolved(HibernateTypeDescriptor typeDescriptor); + } + + public void addResolutionListener(ResolutionListener listener) { + if ( resolutionListeners == null ) { + resolutionListeners = new ArrayList(); + } + resolutionListeners.add( listener ); + } + + private void notifyResolutionListeners() { + if ( resolutionListeners == null ) { + return; + } + + for ( ResolutionListener resolutionListener : resolutionListeners ) { + resolutionListener.typeResolved( this ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBindingEmbedded.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBindingEmbedded.java index 0e8a6f045a..84a0be9e31 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBindingEmbedded.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBindingEmbedded.java @@ -27,6 +27,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.source.spi.MetaAttributeContext; import org.hibernate.metamodel.spi.PluralAttributeElementNature; import org.hibernate.metamodel.spi.PluralAttributeNature; @@ -78,7 +79,7 @@ public class PluralAttributeElementBindingEmbedded } public EmbeddableBinding createBindingContainer( - Aggregate aggregate, + final Aggregate aggregate, MetaAttributeContext metaAttributeContext, SingularAttribute parentReference, Class tuplizerClass) { @@ -115,6 +116,11 @@ public class PluralAttributeElementBindingEmbedded public boolean isAggregated() { return true; } + + @Override + public JavaTypeDescriptor getTypeDescriptor() { + return aggregate.getDescriptor(); + } }; return embeddableBinding; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java index 907fc6770c..15deae744c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java @@ -48,9 +48,9 @@ public class RelationalValueBindingContainer { } public List relationalValueBindings() { - return isListModifiable ? - Collections.unmodifiableList( relationalValueBindings ) : - relationalValueBindings; + return isListModifiable + ? Collections.unmodifiableList( relationalValueBindings ) + : relationalValueBindings; } public List values() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/domain/AbstractAttributeContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/domain/AbstractAttributeContainer.java index 7a088a082b..36110cf71c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/domain/AbstractAttributeContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/domain/AbstractAttributeContainer.java @@ -187,7 +187,9 @@ public abstract class AbstractAttributeContainer implements AttributeContainer, protected void addAttribute(Attribute attribute) { if ( attributeMap.put( attribute.getName(), attribute ) != null ) { - throw new IllegalArgumentException( "Attribute with name [" + attribute.getName() + "] already registered" ); + throw new IllegalArgumentException( + "Attribute with name [" + attribute.getName() + "] already registered : " + getName() + ); } attributeSet.add( attribute ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index eca85d72c9..3d5b402370 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -2147,8 +2147,12 @@ public abstract class AbstractEntityPersister } - protected static boolean isIdentifierAttributeBinding(final AttributeBinding prop){ - return prop.getContainer().seekEntityBinding().getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( prop ); + protected static boolean isIdentifierAttributeBinding(final AttributeBinding prop) { + return prop.getContainer().seekEntityBinding() + .getHierarchyDetails() + .getEntityIdentifier() + .getEntityIdentifierBinding() + .isIdentifierAttributeBinding( prop ); } private void internalInitSubclassPropertyAliasesMap(String path, AttributeBinding[] attributeBindings) { @@ -2289,16 +2293,39 @@ public abstract class AbstractEntityPersister private void initIdentifierPropertyPaths(Mapping mapping) throws MappingException { String idProp = getIdentifierPropertyName(); if ( idProp != null ) { - propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(), - getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping ); + propertyMapping.initPropertyPaths( + idProp, + getIdentifierType(), + getIdentifierColumnNames(), + getIdentifierColumnReaders(), + getIdentifierColumnReaderTemplates(), + null, + mapping + ); } + if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) { - propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), - getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping ); + propertyMapping.initPropertyPaths( + null, + getIdentifierType(), + getIdentifierColumnNames(), + getIdentifierColumnReaders(), + getIdentifierColumnReaderTemplates(), + null, + mapping + ); } + if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) { - propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), - getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping ); + propertyMapping.initPropertyPaths( + ENTITY_ID, + getIdentifierType(), + getIdentifierColumnNames(), + getIdentifierColumnReaders(), + getIdentifierColumnReaderTemplates(), + null, + mapping + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java index 54ad0ad32d..6e54081a01 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java @@ -24,6 +24,7 @@ package org.hibernate.tuple; import org.hibernate.engine.spi.IdentifierValue; +import org.hibernate.engine.spi.SyntheticAttributeHelper; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PostInsertIdentifierGenerator; import org.hibernate.type.Type; @@ -86,8 +87,8 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA boolean embedded, boolean hasIdentifierMapper, IdentifierValue unsavedValue, - IdentifierGenerator identifierGenerator) { - super( null, type ); + IdentifierGenerator identifierGenerator) { + super( SyntheticAttributeHelper.SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME, type ); this.virtual = true; this.embedded = embedded; this.hasIdentifierMapper = hasIdentifierMapper; diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java index 07c3df2e72..062546fc25 100755 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java @@ -32,6 +32,7 @@ import org.hibernate.InstantiationException; import org.hibernate.PropertyNotFoundException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.metamodel.spi.binding.EmbeddableBinding; @@ -61,13 +62,17 @@ public class PojoInstantiator implements Instantiator, Serializable { EmbeddableBinding embeddableBinding, boolean isIdentifierMapper, ReflectionOptimizer.InstantiationOptimizer optimizer) { + final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class ); if ( isIdentifierMapper ) { final EntityIdentifier entityIdentifier = embeddableBinding.seekEntityBinding().getHierarchyDetails().getEntityIdentifier(); - this.mappedClass = entityIdentifier.getLookupClassBinding().getIdClassType(); + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) entityIdentifier.getEntityIdentifierBinding(); + this.mappedClass = cls.classForName( + idBinding.getIdClassMetadata().getIdClassType().getName().toString() + ); } else { - final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class ); this.mappedClass = cls.classForName( embeddableBinding.getAttributeContainer().getDescriptor().getName().toString() ); @@ -102,7 +107,7 @@ public class PojoInstantiator implements Instantiator, Serializable { entityBinding.getProxyInterfaceType().getName().toString() ); } - this.embeddedIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().isNonAggregatedComposite(); + this.embeddedIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE; this.optimizer = optimizer; try { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java index 06d25486d5..d40faf19db 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java @@ -45,8 +45,8 @@ import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; import org.hibernate.metamodel.spi.binding.Cascadeable; -import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.Fetchable; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.persister.entity.EntityPersister; @@ -132,25 +132,24 @@ public final class PropertyFactory { IdentifierGenerator generator, SessionFactoryImplementor sessionFactory) { - final SingularAttributeBinding attributeBinding = - mappedEntity.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); - // TODO: the following will cause an NPE with "virtual" IDs; how should they be set? // (steve) virtual attributes will still be attributes, they will simply be marked as virtual. // see org.hibernate.metamodel.spi.domain.AbstractAttributeContainer.locateOrCreateVirtualAttribute() - final String mappedUnsavedValue = mappedEntity.getHierarchyDetails().getEntityIdentifier().getUnsavedValue(); + final EntityIdentifier idInfo = mappedEntity.getHierarchyDetails().getEntityIdentifier(); + final SingularAttributeBinding attributeBinding = idInfo.getEntityIdentifierBinding().getAttributeBinding(); + final String mappedUnsavedValue = idInfo.getEntityIdentifierBinding().getUnsavedValue(); + + if ( idInfo.getNature() == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding + = (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); - if ( mappedEntity.getHierarchyDetails().getEntityIdentifier().getNature() - == EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { - // the "attribute" will need to be virtual since there is no single - // attribute identifying the identifier final ComponentType type = sessionFactory.getTypeResolver().getTypeFactory().component( new ComponentMetamodel( sessionFactory.getServiceRegistry(), - ( (EmbeddedAttributeBinding) attributeBinding ).getEmbeddableBinding(), + idBinding.getVirtualEmbeddableBinding(), true, - mappedEntity.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().definedIdClass() + idInfo.definesIdClass() ) ); @@ -167,17 +166,22 @@ public final class PropertyFactory { return new IdentifierProperty( type, true, - mappedEntity.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().definedIdClass(), + idInfo.definesIdClass(), unsavedValue, generator ); } else { - final Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); + final EntityIdentifier.AttributeBasedIdentifierBinding idBinding + = (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + + final SingularAttributeBinding idAttributeBinding = idBinding.getAttributeBinding(); + + final Type type = idAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); final IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue( mappedUnsavedValue, - getGetter( attributeBinding, sessionFactory ), + getGetter( idAttributeBinding, sessionFactory ), type, getConstructor( mappedEntity, @@ -186,7 +190,7 @@ public final class PropertyFactory { ); return new IdentifierProperty( - attributeBinding.getAttribute().getName(), + idAttributeBinding.getAttribute().getName(), null, type, false, diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java index d7d4c573b4..1b640b5ea7 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java @@ -67,14 +67,19 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer { boolean isIdentifierMapper) { super( serviceRegistry, component, isIdentifierMapper ); - final EntityIdentifier entityIdentifier = - component.seekEntityBinding().getHierarchyDetails().getEntityIdentifier(); - + final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class ); if ( isIdentifierMapper ) { - this.componentClass = entityIdentifier.getLookupClassBinding().getIdClassType(); + final EntityIdentifier idInfo = component.seekEntityBinding() + .getHierarchyDetails() + .getEntityIdentifier(); + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final EntityIdentifier.IdClassMetadata idClassMetadata = idBinding.getIdClassMetadata(); + this.componentClass = cls.classForName( + idClassMetadata.getIdClassType().getName().toString() + ); } else { - final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class ); this.componentClass = cls.classForName( component.getAttributeContainer().getDescriptor().getName().toString() ); @@ -198,20 +203,37 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer { // TODO: when compositeAttributeBinding is wrapped for an identifier mapper // there will be no need for PropertyFactory.getIdentifierMapperGetter() // and PropertyFactory.getIdentifierMapperSetter + + // this.componentClass is not set yet because of ctor calls - yucky bad design + if ( isIdentifierMapper ) { - // HACK ALERT: when isIdentifierMapper is true, the entity identifier - // must be completely bound when this method is called. - final EntityIdentifier entityIdentifier = - embeddableBinding.seekEntityBinding().getHierarchyDetails().getEntityIdentifier(); + // (steve w/ metamodel) : utterly confused here. What exactly is the + // thing we are trying to accomplish here? it *seems* like we + // are trying to build a getter for the id class (isIdentifierMapper == true), + // so why do we pass in the composite representing the virtual, + // non-aggregated id? why not just pass in the IdClass composite? + // so confusing :) + + final EntityIdentifier idInfo = embeddableBinding.seekEntityBinding() + .getHierarchyDetails() + .getEntityIdentifier(); + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final EntityIdentifier.IdClassMetadata idClassMetadata = idBinding.getIdClassMetadata(); + + final Class componentClass = classForName( + idClassMetadata.getIdClassType().getName().toString() + ); return getGetter( - entityIdentifier.getLookupClassBinding().getIdClassType(), + componentClass, attributeBinding.getAttribute().getName(), - PropertyAccessorFactory.getPropertyAccessor( entityIdentifier.getLookupClassBinding().getAccessStrategy() ) + PropertyAccessorFactory.getPropertyAccessor( + idClassMetadata.getAccessStrategy( attributeBinding.getAttribute().getName() ) + ) ); } else { - final ClassLoaderService cls = serviceRegistry().getService( ClassLoaderService.class ); - final Class clazz = cls.classForName( + final Class clazz = classForName( embeddableBinding.getAttributeContainer().getDescriptor().getName().toString() ); return getGetter( @@ -228,16 +250,25 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer { boolean isIdentifierMapper, AttributeBinding attributeBinding) { if ( isIdentifierMapper ) { - // HACK ALERT: when isIdentifierMapper is true, the entity identifier - // must be completely bound when this method is called. - final EntityIdentifier entityIdentifier = - embeddableBinding.seekEntityBinding().getHierarchyDetails().getEntityIdentifier(); - return getSetter( - entityIdentifier.getLookupClassBinding().getIdClassType(), - attributeBinding.getAttribute().getName(), - PropertyAccessorFactory.getPropertyAccessor( entityIdentifier.getLookupClassBinding().getAccessStrategy() ) - ); + // see discussion about confusing in #buildGetter + final EntityIdentifier idInfo = embeddableBinding.seekEntityBinding() + .getHierarchyDetails() + .getEntityIdentifier(); + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final EntityIdentifier.IdClassMetadata idClassMetadata = idBinding.getIdClassMetadata(); + + final Class componentClass = classForName( + idClassMetadata.getIdClassType().getName().toString() + ); + return getSetter( + componentClass, + attributeBinding.getAttribute().getName(), + PropertyAccessorFactory.getPropertyAccessor( + idClassMetadata.getAccessStrategy( attributeBinding.getAttribute().getName() ) + ) + ); } else { final Class clazz = classForName( diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index 8813ebaaa5..40c79b41db 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -43,6 +43,7 @@ import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PersistEvent; import org.hibernate.event.spi.PersistEventListener; import org.hibernate.id.Assigned; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.loader.PropertyPath; @@ -60,6 +61,7 @@ import org.hibernate.type.ComponentType; import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; import org.hibernate.type.Type; +import org.hibernate.type.TypeFactory; /** @@ -95,9 +97,12 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { this.serviceRegistry = serviceRegistry; this.entityMetamodel = entityMetamodel; - if ( !entityMetamodel.getIdentifierProperty().isVirtual() ) { - idGetter = buildPropertyGetter( mappingInfo.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() ); - idSetter = buildPropertySetter( mappingInfo.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() ); + final EntityIdentifier idInfo = mappingInfo.getHierarchyDetails().getEntityIdentifier(); + if ( idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) { + final EntityIdentifier.AttributeBasedIdentifierBinding identifierBinding = + (EntityIdentifier.AttributeBasedIdentifierBinding) idInfo.getEntityIdentifierBinding(); + idGetter = buildPropertyGetter( identifierBinding.getAttributeBinding() ); + idSetter = buildPropertySetter( identifierBinding.getAttributeBinding() ); } else { idGetter = null; @@ -134,23 +139,19 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { proxyFactory = null; } - final EntityIdentifier entityIdentifier = mappingInfo.getHierarchyDetails().getEntityIdentifier(); - if ( !entityIdentifier.isIdentifierMapper() ) { + if ( !idInfo.definesIdClass() ) { identifierMapperType = null; mappedIdentifierValueMarshaller = null; } else { identifierMapperType = (CompositeType) entityMetamodel.getIdentifierProperty().getType(); - // TODO: this only deals with normal IdClass; still need to deal with MapsId + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding identifierBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + mappedIdentifierValueMarshaller = buildMappedIdentifierValueMarshaller( (ComponentType) identifierMapperType, - (ComponentType) mappingInfo - .getHierarchyDetails() - .getEntityIdentifier() - .getAttributeBinding() - .getHibernateTypeDescriptor() - .getResolvedTypeMapping() + (ComponentType) identifierBinding.getHibernateType() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java index 9d27999012..eb362ce927 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java @@ -192,13 +192,11 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { proxyInterfaces, proxyGetIdentifierMethod, proxySetIdentifierMethod, - entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierMapper() - ? ( CompositeType ) entityBinding - .getHierarchyDetails() + entityBinding.getHierarchyDetails().getEntityIdentifier().definesIdClass() + ? ( CompositeType ) entityBinding.getHierarchyDetails() .getEntityIdentifier() - .getAttributeBinding() - .getHibernateTypeDescriptor() - .getResolvedTypeMapping() + .getEntityIdentifierBinding() + .getHibernateType() : null ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/EmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/EmbeddedIdTest.java index af3370ea30..db18a15341 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/EmbeddedIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/EmbeddedIdTest.java @@ -50,8 +50,7 @@ public class EmbeddedIdTest extends BaseAnnotationBindingTestCase { public void testEmbeddable() { EntityBinding binding = getEntityBinding( User.class ); EntityIdentifier identifier = binding.getHierarchyDetails().getEntityIdentifier(); - assertTrue( !identifier.isNonAggregatedComposite() ); - assertEquals( identifier.getNature(), EntityIdentifierNature.AGGREGATED_COMPOSITE ); + assertEquals( EntityIdentifierNature.AGGREGATED_COMPOSITE, identifier.getNature() ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/IdentifierGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/IdentifierGeneratorTest.java index 0224174ae6..f5bc1051c7 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/IdentifierGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/IdentifierGeneratorTest.java @@ -33,6 +33,7 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.dialect.H2Dialect; import org.hibernate.id.Assigned; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.MultipleHiLoPerTableGenerator; @@ -73,8 +74,7 @@ public class IdentifierGeneratorTest extends BaseAnnotationBindingTestCase { IdentifierGenerator generator =identifier.getIdentifierGenerator(); assertNotNull( generator ); assertEquals( "Wrong generator", Assigned.class, generator.getClass() ); - assertFalse( identifier.isNonAggregatedComposite() ); - + assertEquals( EntityIdentifierNature.SIMPLE, identifier.getNature() ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java index 4c3fbf5f6a..0da447e7e4 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java @@ -135,24 +135,27 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { } assertEquals( 1, directAttributeBindings.size() ); assertSame( - noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), directAttributeBindings.iterator().next() ); assertEquals( 1, noInheritanceEntityBinding.getAttributeBindingClosureSpan() ); Iterator iterator = noInheritanceEntityBinding.attributeBindings().iterator(); assertTrue( iterator.hasNext() ); - assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), iterator.next() ); + assertSame( + noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), + iterator.next() + ); assertFalse( iterator.hasNext() ); AttributeBinding[] attributeBindings = noInheritanceEntityBinding.getAttributeBindingClosure(); assertTrue( attributeBindings.length > 0 ); int index =0; - assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), attributeBindings[index++] ); + assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), attributeBindings[index++] ); assertFalse( index < attributeBindings.length ); attributeBindings = noInheritanceEntityBinding.getEntitiesAttributeBindingClosure(); index = 0; assertTrue( attributeBindings.length > 0 ); - assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), attributeBindings[index++] ); + assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), attributeBindings[index++] ); assertFalse( index < attributeBindings.length ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractBasicBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractBasicBindingTests.java index 7f19074fe5..b539977180 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractBasicBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractBasicBindingTests.java @@ -125,7 +125,7 @@ public abstract class AbstractBasicBindingTests extends BaseUnitTestCase { entityWithManyToOneBinding, attributeBinding, SingularAttributeBinding.class.cast( - simpleEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() + simpleEntityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding() ), defaultManyToOneColumnReferencingId, false @@ -266,11 +266,11 @@ public abstract class AbstractBasicBindingTests extends BaseUnitTestCase { protected void assertIdAndSimpleProperty(EntityBinding entityBinding) { assertNotNull( entityBinding ); assertNotNull( entityBinding.getHierarchyDetails().getEntityIdentifier() ); - assertNotNull( entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() ); + assertNotNull( entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding() ); AttributeBinding idAttributeBinding = entityBinding.locateAttributeBinding( "id" ); assertNotNull( idAttributeBinding ); - assertSame( idAttributeBinding, entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() ); + assertSame( idAttributeBinding, entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding() ); assertSame( LongType.INSTANCE, idAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() ); assertTrue( idAttributeBinding.getAttribute().isSingular() ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractUnsavedValueTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractUnsavedValueTests.java index 0c58284491..c0ba9fab4c 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractUnsavedValueTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/AbstractUnsavedValueTests.java @@ -74,7 +74,7 @@ public abstract class AbstractUnsavedValueTests extends BaseUnitTestCase { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithAssignedId.class.getName() ); // Generator is explicitly "assigned", so unsaved ID value should be "undefined" - assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } @Test @@ -84,7 +84,7 @@ public abstract class AbstractUnsavedValueTests extends BaseUnitTestCase { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithSequenceId.class.getName() ); // Generator is explicitly "increment", so unsaved ID value should be null - assertEquals( null, entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( null, entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } @Test @@ -94,7 +94,7 @@ public abstract class AbstractUnsavedValueTests extends BaseUnitTestCase { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithVersion.class.getName() ); // Generator is explicitly "assigned", so unsaved ID value should be "undefined" - assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } @Test @@ -104,7 +104,7 @@ public abstract class AbstractUnsavedValueTests extends BaseUnitTestCase { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithTimestamp.class.getName() ); // Generator is explicitly "assigned", so unsaved ID value should be "undefined" - assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( "undefined", entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } public abstract void addSourcesForAssignedIdDefaultUnsavedValue(MetadataSources sources); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java index 7f94de27fe..e7e4a33efd 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java @@ -107,9 +107,7 @@ public class SimpleValueBindingTests extends BaseUnitTestCase { entityBinding.getHierarchyDetails().getEntityIdentifier().prepareAsSimpleIdentifier( attributeBinding, new IdentifierGeneratorDefinition( "assigned", "assigned", Collections.emptyMap() ), - "null", - null, - null + "null" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/UnsavedValueHbmTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/UnsavedValueHbmTests.java index 7936275918..da720d49ae 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/UnsavedValueHbmTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/UnsavedValueHbmTests.java @@ -44,7 +44,7 @@ public class UnsavedValueHbmTests extends AbstractUnsavedValueTests { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithAssignedId.class.getName() ); // unsaved-value was mapped as "any"; that should be used, regardless of ID generator. - assertEquals( "any", entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( "any", entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } @Test @@ -54,7 +54,7 @@ public class UnsavedValueHbmTests extends AbstractUnsavedValueTests { MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); EntityBinding entityBinding = metadata.getEntityBinding( EntityWithSequenceId.class.getName() ); // unsaved-value was mapped as "null"; that should be used, regardless of ID generator. - assertEquals( "null", entityBinding.getHierarchyDetails().getEntityIdentifier().getUnsavedValue() ); + assertEquals( "null", entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getUnsavedValue() ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java index f19d926c1a..7c3efa07ad 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java @@ -99,7 +99,7 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa BagType.class, Collection.class, String.class, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "EntityWithBasicCollections_theBag" ), Identifier.toIdentifier( "owner_id" ), FetchTiming.IMMEDIATE, @@ -112,7 +112,7 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa SetType.class, Set.class, String.class, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "EntityWithBasicCollections_theSet" ), Identifier.toIdentifier( "pid" ), FetchTiming.EXTRA_LAZY, diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicEmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicEmbeddedIdTest.java index d5865daabd..08810dc05f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicEmbeddedIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicEmbeddedIdTest.java @@ -42,6 +42,7 @@ import org.junit.Test; import static org.hibernate.metamodel.spi.binding.BindingHelper.locateAttributeBinding; import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; @@ -78,8 +79,8 @@ public class BasicEmbeddedIdTest extends BaseAnnotationBindingTestCase { EntityIdentifierNature.AGGREGATED_COMPOSITE, courseBinding.getHierarchyDetails().getEntityIdentifier().getNature() ); - assertNull( - courseBinding.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().getIdClassType() + assertFalse( + courseBinding.getHierarchyDetails().getEntityIdentifier().definesIdClass() ); // Course should be interpreted as defining 2 attributes: `key` and `title` @@ -94,7 +95,10 @@ public class BasicEmbeddedIdTest extends BaseAnnotationBindingTestCase { "key", EmbeddedAttributeBinding.class ); - SingularAttributeBinding identifierAttribute = courseBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); + SingularAttributeBinding identifierAttribute = courseBinding.getHierarchyDetails() + .getEntityIdentifier() + .getEntityIdentifierBinding() + .getAttributeBinding(); // NOTE : assertSame() does '==' assertSame( keyBinding, identifierAttribute ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicIdClassTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicIdClassTest.java index 664871d339..774392e46f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicIdClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/cid/BasicIdClassTest.java @@ -34,7 +34,9 @@ import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; import org.hibernate.metamodel.spi.binding.EmbeddableBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.RelationalValueBinding; +import org.hibernate.type.StringType; import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase; import org.hibernate.testing.junit4.Resources; @@ -72,7 +74,7 @@ public class BasicIdClassTest extends BaseAnnotationBindingTestCase { @Test @Resources( annotatedClasses = Course.class ) - public void testBasicUsage() { + public void testBasicUsage() throws Exception { // get the Course entity binding EntityBinding courseBinding = getEntityBinding( Course.class ); assertNotNull( courseBinding ); @@ -80,10 +82,14 @@ public class BasicIdClassTest extends BaseAnnotationBindingTestCase { EntityIdentifierNature.NON_AGGREGATED_COMPOSITE, courseBinding.getHierarchyDetails().getEntityIdentifier().getNature() ); - Class idClassClass = courseBinding.getHierarchyDetails().getEntityIdentifier() - .getLookupClassBinding() - .getIdClassType(); - assertNotNull( idClassClass ); + + EntityIdentifier.NonAggregatedCompositeIdentifierBinding identifierBinding = assertTyping( + EntityIdentifier.NonAggregatedCompositeIdentifierBinding.class, + courseBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding() + ); + assertNotNull( identifierBinding.getIdClassMetadata() ); + assertNotNull( identifierBinding.getIdClassMetadata().getIdClassType() ); + assertNotNull( identifierBinding.getIdClassMetadata().getEmbeddableBinding() ); // Course should be interpreted as defining 3 attributes: `department`, `code` and `title` assertEquals( 3, courseBinding.getAttributeBindingClosureSpan() ); @@ -118,32 +124,31 @@ public class BasicIdClassTest extends BaseAnnotationBindingTestCase { assertTrue( - courseBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( - deptAttribute - ) + courseBinding.getHierarchyDetails().getEntityIdentifier(). + getEntityIdentifierBinding() + .isIdentifierAttributeBinding( deptAttribute ) ); assertTrue( - courseBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( - codeAttribute - ) + courseBinding.getHierarchyDetails().getEntityIdentifier() + .getEntityIdentifierBinding() + .isIdentifierAttributeBinding( codeAttribute ) ); - // get the virtual (non-aggregated composite) id attribute + // get the non-aggregated composite id (virtual) attribute EmbeddedAttributeBinding identifierAttribute = (EmbeddedAttributeBinding) courseBinding.getHierarchyDetails() .getEntityIdentifier() + .getEntityIdentifierBinding() .getAttributeBinding(); assertNotNull( identifierAttribute ); - // NOTE : assertSame() does `==` + assertTrue( identifierAttribute.getAttribute().isSynthetic() ); EmbeddableBinding virtualEmbeddable = identifierAttribute.getEmbeddableBinding(); assertEquals( 2, virtualEmbeddable.attributeBindingSpan() ); for ( AttributeBinding subAttributeBinding : virtualEmbeddable.attributeBindings() ) { - assertTrue( - subAttributeBinding == deptAttribute - || subAttributeBinding == codeAttribute - ); + assertNotNull( subAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() ); + assertEquals( StringType.INSTANCE, subAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java index 2166b83d4d..1dc6d2768f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java @@ -104,7 +104,7 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn BagType.class, Collection.class, simpleEntityBinding, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "theBagOwner" ), FetchTiming.DELAYED, true @@ -116,7 +116,7 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn SetType.class, Set.class, simpleEntityBinding, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "theSetOwner" ), FetchTiming.IMMEDIATE, false @@ -128,7 +128,7 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn ListType.class, List.class, simpleEntityBinding, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "theListOwner" ), FetchTiming.IMMEDIATE, false @@ -140,7 +140,7 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn MapType.class, Map.class, simpleEntityBinding, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(), Identifier.toIdentifier( "theMapOwner" ), FetchTiming.DELAYED, false diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/A_PK.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/A_PK.java index 791d6cfc97..f224e4d536 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/A_PK.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/A_PK.java @@ -1,6 +1,7 @@ // $Id$ package org.hibernate.test.annotations.fkcircularity; import java.io.Serializable; +import javax.persistence.Embeddable; import javax.persistence.ManyToOne; /** @@ -9,6 +10,7 @@ import javax.persistence.ManyToOne; * @author Hardy Ferentschik * */ +@Embeddable @SuppressWarnings("serial") public class A_PK implements Serializable { public D d; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/D_PK.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/D_PK.java index 94bf1d7997..0faef4b021 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/D_PK.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/D_PK.java @@ -10,6 +10,7 @@ import javax.persistence.ManyToOne; * @author Hardy Ferentschik * */ +@Embeddable @SuppressWarnings("serial") public class D_PK implements Serializable{ private C c; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/FkCircularityTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/FkCircularityTest.java index 32c50eb375..8bbc0ad42b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/FkCircularityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/fkcircularity/FkCircularityTest.java @@ -14,9 +14,11 @@ public class FkCircularityTest extends BaseUnitTestCase { public void testJoinedSublcassesInPK() { MetadataSources metadataSources = new MetadataSources() .addAnnotatedClass( A.class ) + .addAnnotatedClass( A_PK.class ) .addAnnotatedClass( B.class ) .addAnnotatedClass( C.class ) - .addAnnotatedClass( D.class ); + .addAnnotatedClass( D.class ) + .addAnnotatedClass( D_PK.class ); metadataSources.buildMetadata(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdClassTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdClassTest.java index df0725c997..1ecc1060aa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdClassTest.java @@ -23,13 +23,13 @@ */ package org.hibernate.test.annotations.id; -import org.junit.Test; - import org.hibernate.Session; import org.hibernate.Transaction; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.test.annotations.id.entities.Location; import org.hibernate.test.annotations.id.entities.Tower; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/IdClassTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/IdClassTest.java index f0865d5e2f..887fc10e0a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/IdClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/IdClassTest.java @@ -29,6 +29,7 @@ import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.test.annotations.id.sequences.entities.Location; import org.hibernate.test.annotations.id.sequences.entities.Tower; +import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/manytoone/ManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/manytoone/ManyToOneTest.java index 69331a4063..f76f9b2114 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/manytoone/ManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/manytoone/ManyToOneTest.java @@ -50,7 +50,6 @@ import static org.junit.Assert.assertTrue; /** * @author Emmanuel Bernard */ -@FailureExpectedWithNewMetamodel public class ManyToOneTest extends BaseCoreFunctionalTestCase { @Test public void testEager() throws Exception { @@ -219,6 +218,10 @@ public class ManyToOneTest extends BaseCoreFunctionalTestCase { } @Test + @FailureExpectedWithNewMetamodel( + jiraKey = "HHH-9055", + message = "Problem with column ordering and JDBC parameter binding" + ) public void testCompositeFK() throws Exception { Session s; Transaction tx; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/mappedsuperclass/intermediate/IntermediateMappedSuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/mappedsuperclass/intermediate/IntermediateMappedSuperclassTest.java index c1404b90e0..92f1c55988 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/mappedsuperclass/intermediate/IntermediateMappedSuperclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/mappedsuperclass/intermediate/IntermediateMappedSuperclassTest.java @@ -36,7 +36,6 @@ import static org.junit.Assert.assertEquals; /** * @author Steve Ebersole */ -@FailureExpectedWithNewMetamodel public class IntermediateMappedSuperclassTest extends BaseCoreFunctionalTestCase { @Override protected Class[] getAnnotatedClasses() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/TupleSupportTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/TupleSupportTest.java index c81387ba95..0e4caaa4a3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/TupleSupportTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/TupleSupportTest.java @@ -102,7 +102,6 @@ public class TupleSupportTest extends BaseUnitTestCase { } @Test - @FailureExpectedWithNewMetamodel public void testImplicitTupleNotInList() { final String hql = "from TheEntity e where e.compositeValue not in (:p1,:p2)"; HQLQueryPlan queryPlan = ( (SessionFactoryImplementor) sessionFactory ).getQueryPlanCache() diff --git a/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassTest.java b/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassTest.java index 0fc9c46699..37492c6b4a 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassTest.java @@ -28,7 +28,6 @@ import org.junit.Test; import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertEquals; @@ -36,7 +35,6 @@ import static org.junit.Assert.assertEquals; /** * @author Gavin King */ -@FailureExpectedWithNewMetamodel public class IdClassTest extends BaseCoreFunctionalTestCase { public String[] getMappings() { return new String[] { "idclass/Customer.hbm.xml" }; diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/MapTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/MapTest.java index 7b06aed439..f565ddfb06 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/MapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/MapTest.java @@ -39,6 +39,10 @@ import org.hibernate.testing.FailureExpectedWithNewMetamodel; import static org.junit.Assert.assertTrue; +@FailureExpectedWithNewMetamodel( + jiraKey = "HHH-9055", + message = "Caused by: org.hibernate.MappingException: broken column mapping [Commento#marelo.id]; expecting 1 columns, but type defined 2" +) public class MapTest extends LegacyTestCase { @Override public String[] getMappings() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java index bf9a7c8f4b..a31b9a74a2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java @@ -22,6 +22,7 @@ import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.TimesTenDialect; import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.Test; @@ -695,6 +696,10 @@ public class SQLLoaderTest extends LegacyTestCase { @Test @TestForIssue( jiraKey = "HHH-21" ) + @FailureExpectedWithNewMetamodel( + jiraKey = "HHH-9055", + message = "The load/check does not work" + ) public void testCompositeIdId() throws HibernateException, SQLException { Session s = openSession(); s.beginTransaction(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/loadplans/plans/LoadPlanStructureAssertionTest.java b/hibernate-core/src/test/java/org/hibernate/test/loadplans/plans/LoadPlanStructureAssertionTest.java index 5655a3eeb4..e194e8490a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/loadplans/plans/LoadPlanStructureAssertionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/loadplans/plans/LoadPlanStructureAssertionTest.java @@ -98,7 +98,6 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase { } @Test - @FailureExpectedWithNewMetamodel public void testEncapsulatedCompositeIdNoFetches1() { // CardField is an entity with a composite identifier mapped via a @EmbeddedId class (CardFieldPK) defining // a @ManyToOne @@ -120,7 +119,6 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase { } @Test - @FailureExpectedWithNewMetamodel public void testEncapsulatedCompositeIdNoFetches2() { // Parent is an entity with a composite identifier mapped via a @EmbeddedId class (ParentPK) which is defined // using just basic types (strings, ints, etc) diff --git a/hibernate-core/src/test/java/org/hibernate/test/loadplans/walking/CompositesWalkingTest.java b/hibernate-core/src/test/java/org/hibernate/test/loadplans/walking/CompositesWalkingTest.java index 0d0f064704..76465f0220 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/loadplans/walking/CompositesWalkingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/loadplans/walking/CompositesWalkingTest.java @@ -27,6 +27,8 @@ import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.walking.spi.MetamodelGraphWalker; + +import org.hibernate.test.annotations.collectionelement.LocalizedString; import org.hibernate.test.annotations.collectionelement.TestCourse; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Test; @@ -42,6 +44,7 @@ public class CompositesWalkingTest extends BaseUnitTestCase { public void testEntityComposite() { final SessionFactory sf = new Configuration() .addAnnotatedClass( TestCourse.class ) + .addAnnotatedClass( LocalizedString.class ) .buildSessionFactory(); try { final EntityPersister ep = (EntityPersister) sf.getClassMetadata( TestCourse.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/mapping/AliasTest.java b/hibernate-core/src/test/java/org/hibernate/test/mapping/AliasTest.java index ea0d1fd8dd..06ab1e3b34 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/mapping/AliasTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/mapping/AliasTest.java @@ -67,8 +67,8 @@ public class AliasTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue( jiraKey = "HHH-8371" ) @FailureExpectedWithNewMetamodel( - jiraKey = "HHH-9048", - message = "I think its the same underlying problem as HHH-9048; here the manifestation is in @IdClass with the basic form of the to-one pk" + jiraKey = "HHH-9055", + message = "Problems getting/setting id values at runtime" ) public void testUnderscoreInColumnName() throws Throwable { final Session s = openSession(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/metamodel/derivedid/e1/a/MappingTest.java b/hibernate-core/src/test/java/org/hibernate/test/metamodel/derivedid/e1/a/MappingTest.java index d6b04d786d..94a17707d0 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/metamodel/derivedid/e1/a/MappingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/metamodel/derivedid/e1/a/MappingTest.java @@ -27,6 +27,7 @@ import org.hibernate.id.EntityIdentifierNature; import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.type.LongType; import org.hibernate.type.Type; @@ -36,6 +37,7 @@ import org.hibernate.testing.junit4.ExtraAssertions; import org.hibernate.test.metamodel.derivedid.e1.Employee; import org.junit.Test; +import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -59,17 +61,24 @@ public class MappingTest extends BaseUnitTestCase { EntityIdentifierNature.SIMPLE, employeeBinding.getHierarchyDetails().getEntityIdentifier().getNature() ); - SingularAttributeBinding empIdAttrBinding = employeeBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(); + SingularAttributeBinding empIdAttrBinding = employeeBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().getAttributeBinding(); Type empIdType = empIdAttrBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); assertNotNull( empIdType ); - ExtraAssertions.assertTyping( LongType.class, empIdType ); + assertTyping( LongType.class, empIdType ); EntityBinding depBinding = metadata.getEntityBinding( Dependent.class.getName() ); assertEquals( EntityIdentifierNature.NON_AGGREGATED_COMPOSITE, depBinding.getHierarchyDetails().getEntityIdentifier().getNature() ); - assertNotNull( depBinding.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().getIdClassType() ); + EntityIdentifier.NonAggregatedCompositeIdentifierBinding identifierBinding = assertTyping( + EntityIdentifier.NonAggregatedCompositeIdentifierBinding.class, + depBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding() + ); + + assertNotNull( identifierBinding.getIdClassMetadata() ); + assertNotNull( identifierBinding.getIdClassMetadata().getIdClassType() ); + assertNotNull( identifierBinding.getIdClassMetadata().getEmbeddableBinding() ); // The issue here is the lack of understanding that the IdClass attributes // are not the same types as the entity attribute(s). diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/metamodel/builder/MetamodelBuilder.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/metamodel/builder/MetamodelBuilder.java index 181811455e..f68eff5a43 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/metamodel/builder/MetamodelBuilder.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/metamodel/builder/MetamodelBuilder.java @@ -40,6 +40,7 @@ import org.hibernate.HibernateException; import org.hibernate.annotations.common.AssertionFailure; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.id.EntityIdentifierNature; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.jpa.internal.metamodel.AbstractIdentifiableType; import org.hibernate.jpa.internal.metamodel.AbstractManagedType; @@ -51,8 +52,10 @@ import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; +import org.hibernate.metamodel.spi.binding.EmbeddableBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.EntityIdentifier; import org.hibernate.metamodel.spi.binding.HierarchyDetails; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.metamodel.spi.domain.Entity; @@ -135,13 +138,15 @@ public class MetamodelBuilder { final Class javaType = cls.classForName( entityBinding.getEntity().getDescriptor().getName().toString() ); final AbstractIdentifiableType superType = locateOrBuildSuperType( entityBinding.getEntity().getSuperType(), entityBinding ); + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); + EntityTypeImpl entityType = new EntityTypeImpl( javaType, superType, entityBinding.getEntityName(), entityBinding.getJpaEntityName(), - entityBinding.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().definedIdClass(), - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() != null, + idInfo.definesIdClass(), + idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE, entityBinding.getHierarchyDetails().isVersioned() ); @@ -208,14 +213,18 @@ public class MetamodelBuilder { @SuppressWarnings("unchecked") private MappedSuperclassTypeImpl buildMappedSuperclassType(MappedSuperclass mappedSuperclass, EntityBinding entityBinding) { final Class javaType = loadClass( mappedSuperclass.getDescriptor() ); - final AbstractIdentifiableType superSuperType = locateOrBuildSuperType( mappedSuperclass.getSuperType(), entityBinding ); + final AbstractIdentifiableType superSuperType = locateOrBuildSuperType( + mappedSuperclass.getSuperType(), + entityBinding + ); + + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl( javaType, superSuperType, - entityBinding.getHierarchyDetails().getEntityIdentifier().isNonAggregatedComposite() - && entityBinding.getHierarchyDetails().getEntityIdentifier().getIdClassClass() != null, - entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() != null, + idInfo.definesIdClass(), + idInfo.getNature() != EntityIdentifierNature.NON_AGGREGATED_COMPOSITE, entityBinding.getHierarchyDetails().isVersioned() ); @@ -292,7 +301,9 @@ public class MetamodelBuilder { applyVersionAttribute( hierarchical, entityBinding.getHierarchyDetails(), jpaDescriptor ); for ( AttributeBinding attributeBinding : entityBinding.attributeBindings() ) { - if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) { + if ( entityBinding.getHierarchyDetails().getEntityIdentifier().getEntityIdentifierBinding().isIdentifierAttributeBinding( + attributeBinding + ) ) { continue; } if ( entityBinding.getHierarchyDetails().isVersioned() ) { @@ -323,9 +334,15 @@ public class MetamodelBuilder { Hierarchical descriptor, HierarchyDetails hierarchyDetails, AbstractIdentifiableType jpaDescriptor) { - switch ( hierarchyDetails.getEntityIdentifier().getNature() ) { + final EntityIdentifier idInfo = hierarchyDetails.getEntityIdentifier(); + final EntityIdentifier.Binding idBinding = idInfo.getEntityIdentifierBinding(); + + switch ( idBinding.getNature() ) { case SIMPLE: { - SingularAttributeBinding idAttributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding(); + final EntityIdentifier.SimpleIdentifierBinding simpleIdBinding = + (EntityIdentifier.SimpleIdentifierBinding) idBinding; + final SingularAttributeBinding idAttributeBinding = + simpleIdBinding.getAttributeBinding(); if ( idAttributeBinding != null ) { if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { //noinspection unchecked @@ -337,8 +354,11 @@ public class MetamodelBuilder { break; } case AGGREGATED_COMPOSITE: { - EmbeddedAttributeBinding idAttributeBinding = - (EmbeddedAttributeBinding) hierarchyDetails.getEntityIdentifier().getAttributeBinding(); + final EntityIdentifier.AggregatedCompositeIdentifierBinding cIdBinding = + (EntityIdentifier.AggregatedCompositeIdentifierBinding) idBinding; + final EmbeddedAttributeBinding idAttributeBinding = + (EmbeddedAttributeBinding) cIdBinding.getAttributeBinding(); + if ( idAttributeBinding != null ) { if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { //noinspection unchecked @@ -350,19 +370,17 @@ public class MetamodelBuilder { break; } default: { - // nature == (non-aggregated) COMPOSITE - EmbeddedAttributeBinding idAttributeBinding = - (EmbeddedAttributeBinding) hierarchyDetails.getEntityIdentifier().getAttributeBinding(); - if ( idAttributeBinding != null ) { - if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { - Set idClassAttributes = new HashSet(); - for ( AttributeBinding idClassAttributeBinding : idAttributeBinding.getEmbeddableBinding().attributeBindings() ) { - idClassAttributes.add( attributeBuilder.buildIdAttribute( jpaDescriptor, idClassAttributeBinding ) ); - } - //noinspection unchecked - jpaDescriptor.getBuilder().applyIdClassAttributes( idClassAttributes ); - } + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding cIdBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idBinding; + final EmbeddableBinding virtualIdEmbeddableBinding = + cIdBinding.getVirtualEmbeddableBinding(); + + Set idClassAttributes = new HashSet(); + for ( AttributeBinding attributeBinding : virtualIdEmbeddableBinding.attributeBindings() ) { + idClassAttributes.add( attributeBuilder.buildIdAttribute( jpaDescriptor, attributeBinding ) ); } + //noinspection unchecked + jpaDescriptor.getBuilder().applyIdClassAttributes( idClassAttributes ); } } } diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/convert/SimpleEmbeddableOverriddenConverterTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/convert/SimpleEmbeddableOverriddenConverterTest.java index 24a75e6bf6..f969a9d461 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/convert/SimpleEmbeddableOverriddenConverterTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/convert/SimpleEmbeddableOverriddenConverterTest.java @@ -42,7 +42,6 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.CompositeType; import org.hibernate.type.StringType; import org.hibernate.type.Type; -import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Test; @@ -58,7 +57,6 @@ public class SimpleEmbeddableOverriddenConverterTest extends BaseUnitTestCase { * Test outcome of annotations exclusively. */ @Test - @FailureExpectedWithNewMetamodel( message = "@Embeddables not automatically indexed by Jandex" ) public void testSimpleConvertOverrides() { final PersistenceUnitDescriptorAdapter pu = new PersistenceUnitDescriptorAdapter() { @Override diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java index 17ad0e2341..0f1c29b1df 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java @@ -34,7 +34,6 @@ import javax.persistence.criteria.Root; import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest; -import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -43,7 +42,6 @@ import junit.framework.Assert; /** * @author Erich Heard */ -@FailureExpectedWithNewMetamodel( jiraKey = "HHH-9055" ) public class IdClassPredicateTest extends AbstractMetamodelSpecificTest { @Override diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/IdMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/IdMetadataGenerator.java index 10e9a4778c..ae976e5d68 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/IdMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/IdMetadataGenerator.java @@ -37,6 +37,7 @@ import org.hibernate.envers.internal.entities.mapper.id.SimpleIdMapperBuilder; import org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper; import org.hibernate.id.EntityIdentifierNature; import org.hibernate.metamodel.spi.binding.AttributeBinding; +import org.hibernate.metamodel.spi.binding.EmbeddableBinding; import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityIdentifier; @@ -65,14 +66,14 @@ public final class IdMetadataGenerator { @SuppressWarnings({"unchecked"}) private boolean addIdProperties( Element parent, - EmbeddedAttributeBinding embeddedAttributeBinding, + EmbeddableBinding embeddableBinding, SimpleMapperBuilder mapper, boolean key, boolean audited) { //if ( embeddedAttributeBinding.getAttribute().isSynthetic() ) { // return true; //} - for ( AttributeBinding attributeBinding : embeddedAttributeBinding.getEmbeddableBinding().attributeBindings() ) { + for ( AttributeBinding attributeBinding : embeddableBinding.attributeBindings() ) { final Type propertyType = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); final boolean added; if ( propertyType instanceof ManyToOneType ) { @@ -127,16 +128,20 @@ public final class IdMetadataGenerator { // return null; //} - final EntityIdentifier entityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier(); + final EntityIdentifier idInfo = entityBinding.getHierarchyDetails().getEntityIdentifier(); SimpleIdMapperBuilder mapper; - if ( entityIdentifier.getLookupClassBinding().definedIdClass() ) { + if ( idInfo.definesIdClass() ) { // Multiple id - final Class componentClass = entityIdentifier.getLookupClassBinding().getIdClassType(); + final EntityIdentifier.NonAggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.NonAggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + final Class componentClass = context.getClassLoaderService().classForName( + idBinding.getIdClassMetadata().getIdClassType().getName().toString() + ); mapper = new MultipleIdMapper( componentClass ); if ( !addIdProperties( relIdMapping, - (EmbeddedAttributeBinding) entityIdentifier.getAttributeBinding(), + idBinding.getVirtualEmbeddableBinding(), mapper, false, audited @@ -147,7 +152,7 @@ public final class IdMetadataGenerator { // null mapper - the mapping where already added the first time, now we only want to generate the xml if ( !addIdProperties( origIdMapping, - (EmbeddedAttributeBinding) entityIdentifier.getAttributeBinding(), + idBinding.getVirtualEmbeddableBinding(), null, true, audited @@ -155,16 +160,19 @@ public final class IdMetadataGenerator { return null; } } - else if ( entityIdentifier.getNature() == EntityIdentifierNature.AGGREGATED_COMPOSITE ) { + else if ( idInfo.getNature() == EntityIdentifierNature.AGGREGATED_COMPOSITE ) { // Embeddable id + final EntityIdentifier.AggregatedCompositeIdentifierBinding idBinding = + (EntityIdentifier.AggregatedCompositeIdentifierBinding) idInfo.getEntityIdentifierBinding(); + // TODO: get rid of classloading. final Class embeddableClass = context.getClassLoaderService().classForName( - entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor().getJavaTypeDescriptor().getName().toString() + idBinding.getAttributeBinding().getEmbeddableBinding().getTypeDescriptor().getName().toString() ); - mapper = new EmbeddedIdMapper( getIdPropertyData( entityIdentifier.getAttributeBinding() ), embeddableClass ); + mapper = new EmbeddedIdMapper( getIdPropertyData( idBinding.getAttributeBinding() ), embeddableClass ); if ( !addIdProperties( relIdMapping, - (EmbeddedAttributeBinding) entityIdentifier.getAttributeBinding(), + idBinding.getAttributeBinding().getEmbeddableBinding(), mapper, false, audited @@ -175,7 +183,7 @@ public final class IdMetadataGenerator { // null mapper - the mapping where already added the first time, now we only want to generate the xml if ( !addIdProperties( origIdMapping, - (EmbeddedAttributeBinding) entityIdentifier.getAttributeBinding(), + idBinding.getAttributeBinding().getEmbeddableBinding(), null, true, audited @@ -184,16 +192,19 @@ public final class IdMetadataGenerator { } } else { + final EntityIdentifier.SimpleIdentifierBinding idBinding = + (EntityIdentifier.SimpleIdentifierBinding) idInfo.getEntityIdentifierBinding(); + // Single id mapper = new SingleIdMapper(); // Last but one parameter: ids are always insertable mainGenerator.getBasicMetadataGenerator().addBasic( relIdMapping, - getIdPersistentPropertyAuditingData( entityIdentifier.getAttributeBinding() ), - entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor(), - entityIdentifier.getAttributeBinding().getValues(), - entityIdentifier.getAttributeBinding().isIncludedInInsert(), + getIdPersistentPropertyAuditingData( idBinding.getAttributeBinding() ), + idBinding.getAttributeBinding().getHibernateTypeDescriptor(), + idBinding.getAttributeBinding().getValues(), + idBinding.getAttributeBinding().isIncludedInInsert(), mapper, false ); @@ -201,10 +212,10 @@ public final class IdMetadataGenerator { // null mapper - the mapping where already added the first time, now we only want to generate the xml mainGenerator.getBasicMetadataGenerator().addBasic( origIdMapping, - getIdPersistentPropertyAuditingData( entityIdentifier.getAttributeBinding() ), - entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor(), - entityIdentifier.getAttributeBinding().getValues(), - entityIdentifier.getAttributeBinding().isIncludedInInsert(), + getIdPersistentPropertyAuditingData( idBinding.getAttributeBinding() ), + idBinding.getAttributeBinding().getHibernateTypeDescriptor(), + idBinding.getAttributeBinding().getValues(), + idBinding.getAttributeBinding().isIncludedInInsert(), null, true );