diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java index 89f3464631..123773632d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java @@ -33,7 +33,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -59,6 +58,8 @@ import org.hibernate.id.IdentityGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.metamodel.internal.EntityHierarchyHelper.LocalBindingContextExecutionContext; +import org.hibernate.metamodel.internal.EntityHierarchyHelper.LocalBindingContextExecutor; import org.hibernate.internal.FilterConfiguration; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; @@ -161,7 +162,6 @@ import org.hibernate.metamodel.spi.source.SequentialPluralAttributeIndexSource; import org.hibernate.metamodel.spi.source.SimpleIdentifierSource; import org.hibernate.metamodel.spi.source.SingularAttributeSource; import org.hibernate.metamodel.spi.source.Sortable; -import org.hibernate.metamodel.spi.source.SubclassEntitySource; import org.hibernate.metamodel.spi.source.TableSource; import org.hibernate.metamodel.spi.source.TableSpecificationSource; import org.hibernate.metamodel.spi.source.ToOneAttributeSource; @@ -206,12 +206,9 @@ public class Binder { private final SourceIndex sourceIndex = new SourceIndex(); // todo : apply org.hibernate.metamodel.MetadataSources.getExternalCacheRegionDefinitions() - // the inheritanceTypes and entityModes correspond with bindingContexts - private final LinkedList bindingContexts = new LinkedList(); - private final LinkedList inheritanceTypes = new LinkedList(); - private final LinkedList entityModes = new LinkedList(); // helpers + private final EntityHierarchyHelper entityHierarchyHelper; private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class private final ForeignKeyHelper foreignKeyHelper; @@ -219,6 +216,7 @@ public class Binder { final IdentifierGeneratorFactory identifierGeneratorFactory) { this.metadata = metadata; this.identifierGeneratorFactory = identifierGeneratorFactory; + this.entityHierarchyHelper = new EntityHierarchyHelper( metadata ); this.typeHelper = new HibernateTypeHelper( this, metadata ); this.foreignKeyHelper = new ForeignKeyHelper( this ); this.nameNormalizer = metadata.getObjectNameNormalizer(); @@ -230,10 +228,6 @@ public class Binder { * @param entityHierarchies The entity hierarchies resolved from mappings */ public void addEntityHierarchies(final Iterable entityHierarchies) { - inheritanceTypes.clear(); - entityModes.clear(); - bindingContexts.clear(); - LocalBindingContextExecutor executor = new LocalBindingContextExecutor() { @Override public void execute(LocalBindingContextExecutionContext bindingContextContext) { @@ -249,14 +243,13 @@ public class Binder { entityHierarchy.getRootEntitySource().getEntityName(), entityHierarchy ); - applyToEntityHierarchy( entityHierarchy, executor, executor ); + entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, executor, executor ); } } public void bindEntityHierarchies() { - bindingContexts.clear(); - inheritanceTypes.clear(); - entityModes.clear(); + + applyToAllEntityHierarchies( resolveAssociationSourcesExecutor() ); bindEntityHierarchiesExcludingNonIdAttributeBindings(); @@ -281,6 +274,27 @@ public class Binder { // if so, mark the many-to-one as a logical one-to-one. } + private InheritanceType inheritanceType() { + return entityHierarchyHelper.inheritanceType(); + } + + private EntityMode entityMode() { + return entityHierarchyHelper.entityMode(); + } + + // TODO: make this private + LocalBindingContext bindingContext() { + return entityHierarchyHelper.bindingContext(); + } + + private void applyToAllEntityHierarchies(LocalBindingContextExecutor executor) { + applyToAllEntityHierarchies( executor, executor ); + } + + private void applyToAllEntityHierarchies(LocalBindingContextExecutor rootExecutor, LocalBindingContextExecutor subExecutor) { + entityHierarchyHelper.applyToAllEntityHierarchies( entityHierarchiesByRootEntityName.values(), rootExecutor, subExecutor ); + } + private void bindEntityHierarchiesExcludingNonIdAttributeBindings() { LocalBindingContextExecutor rootEntityCallback = new LocalBindingContextExecutor() { @Override @@ -324,12 +338,12 @@ public class Binder { unresolvedEntityHierarchies.add( entityHierarchy ); } else { - applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback ); + entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback ); } } for ( EntityHierarchy entityHierarchy : unresolvedEntityHierarchies ) { - applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback ); + entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback ); } } @@ -369,6 +383,15 @@ public class Binder { (AttributeBindingContainer) entityBinding.locateAttributeBindingByPath( containerPath, false ); } + private LocalBindingContextExecutor resolveAssociationSourcesExecutor() { + return new LocalBindingContextExecutor() { + @Override + public void execute(LocalBindingContextExecutionContext bindingContextContext) { + sourceIndex.resolveAssociationSources( bindingContextContext.getEntitySource().getEntityName() ); + } + }; + } + private LocalBindingContextExecutor bindSingularAttributesExecutor( final SingularAttributeSource.Nature nature) { return new LocalBindingContextExecutor() { @@ -443,12 +466,26 @@ public class Binder { null, // TODO: don't have the default value at this point; shouldn't be needed... compositeAttributeBinding ); + if ( compositeAttributeBinding.getContainer() instanceof CompositeAttributeBindingContainer ) { + final CompositeAttributeBinding parentCompositeAttributeBinding = + (CompositeAttributeBinding) compositeAttributeBinding.seekEntityBinding().locateAttributeBinding( + ( compositeAttributeBinding.getContainer() ).getPathBase() + ); + final ComponentAttributeSource parentCompositeAttributeSource = + (ComponentAttributeSource) sourceIndex.attributeSource( + parentCompositeAttributeBinding.seekEntityBinding().getEntityName(), + parentCompositeAttributeBinding.getPathBase() + ); + completeCompositeAttributeBindingIfPossible( + parentCompositeAttributeBinding, + parentCompositeAttributeSource + ); + } } } } - private LocalBindingContextExecutor bindPluralAttributesExecutor( - final boolean isInverse) { + private LocalBindingContextExecutor bindPluralAttributesExecutor(final boolean isInverse) { return new LocalBindingContextExecutor() { @Override public void execute(LocalBindingContextExecutionContext bindingContextContext) { @@ -462,28 +499,27 @@ public class Binder { } private void bindPluralAttributes( - final AttributeBindingContainer attributeBindingContainer, - final AttributeSourceContainer attributeSourceContainer, + final EntityBinding entityBinding, + final EntitySource entitySource, final boolean isInverse) { - for ( AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) { - if ( attributeSource.isSingular() ) { - SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource; - if ( singularAttributeSource.getNature() == SingularAttributeSource.Nature.COMPOSITE ) { - final ComponentAttributeSource compositeAttributeSource = (ComponentAttributeSource) attributeSource; - final CompositeAttributeBinding compositeAttributeBinding = - (CompositeAttributeBinding) attributeBindingContainer.locateAttributeBinding( attributeSource.getName() ); - bindPluralAttributes( - compositeAttributeBinding, - compositeAttributeSource, - isInverse - ); - completeCompositeAttributeBindingIfPossible( compositeAttributeBinding, compositeAttributeSource ); - } - } - else { - if ( isInverse == ( (PluralAttributeSource) attributeSource ).isInverse() ) { - bindAttribute( attributeBindingContainer, attributeSource ); - } + Map map = sourceIndex.getPluralAttributeSources( + entityBinding.getEntityName(), + isInverse + ); + for ( Map.Entry entry : map.entrySet() ){ + final SourceIndex.AttributeSourceKey attributeSourceKey = entry.getKey(); + final PluralAttributeSource attributeSource = entry.getValue(); + final AttributeBindingContainer attributeBindingContainer = + locateAttributeBindingContainer( entityBinding, attributeSourceKey.containerPath() ); + bindAttribute( attributeBindingContainer, attributeSource ); + if ( attributeBindingContainer instanceof CompositeAttributeBinding ) { + final CompositeAttributeBinding compositeAttributeBinding = (CompositeAttributeBinding) attributeBindingContainer; + final ComponentAttributeSource compositeAttributeSource = + (ComponentAttributeSource) sourceIndex.attributeSource( + entityBinding.getEntityName(), + compositeAttributeBinding.getPathBase() + ); + completeCompositeAttributeBindingIfPossible( compositeAttributeBinding, compositeAttributeSource ); } } } @@ -524,17 +560,15 @@ public class Binder { final EntityBinding superEntityBinding, final EntitySource entitySource) { // Create binding - final InheritanceType inheritanceType = inheritanceTypes.peek(); - final EntityMode entityMode = entityModes.peek(); final EntityBinding entityBinding = entitySource instanceof RootEntitySource ? new EntityBinding( - inheritanceType, - entityMode + inheritanceType(), + entityMode() ) : new EntityBinding( superEntityBinding ); // Create domain entity - final String entityClassName = entityMode == EntityMode.POJO ? entitySource.getClassName() : null; + final String entityClassName = entityMode() == EntityMode.POJO ? entitySource.getClassName() : null; LocalBindingContext bindingContext = bindingContext(); entityBinding.setEntity( new Entity( @@ -621,7 +655,7 @@ public class Binder { private void resolveEntityLaziness( final EntityBinding entityBinding, final EntitySource entitySource) { - if ( entityModes.peek() == EntityMode.POJO ) { + if ( entityMode() == EntityMode.POJO ) { final String proxy = entitySource.getProxy(); if ( proxy == null ) { if ( entitySource.isLazy() ) { @@ -1545,16 +1579,6 @@ public class Binder { final AttributeBindingContainer attributeBindingContainer, final PluralAttributeSource attributeSource) { final PluralAttributeSource.Nature nature = attributeSource.getNature(); - if ( attributeSource.getMappedBy() != null ) { - attributeSource.resolvePluralAttributeElementSource( - new PluralAttributeElementSourceResolver.PluralAttributeElementSourceResolutionContext() { - @Override - public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) { - return sourceIndex.attributeSource( referencedEntityName, mappedBy ); - } - } - ); - } final PluralAttribute attribute = attributeBindingContainer.getAttributeContainer().locatePluralAttribute( attributeSource.getName() ); final AbstractPluralAttributeBinding attributeBinding; @@ -2164,33 +2188,26 @@ public class Binder { ); final PluralAttributeKeyBinding keyBinding = attributeBinding.getPluralAttributeKeyBinding(); keyBinding.setInverse( isInverse ); - String oppositeAttributeName = null; + final AttributeSource oppositeAttributeSource; if ( attributeSource.getMappedBy() == null ) { - final String path; - //if ( StringHelper.isEmpty( attributeBinding.getContainer().getPathBase() ) ) { - path = createAttributePath( attributeBinding ); - //} - //else { - // path = attributeBinding.getContainer().getPathBase() + '.' + attributeBinding.getAttribute().getName(); - //} - // determine if there is an association that is mappedBy this one - EntitySource referencedEntitySource = sourceIndex.entitySource( referencedEntityBinding.getEntityName() ); - - for ( AttributeSource referencedAttributeSource : referencedEntitySource.attributeSources() ) { - // TODO: move this somewhere else or index beforehand. - // TODO: deal with mappedBy w/in CompositeAttributeBindings. - if ( referencedAttributeSource instanceof PluralAttributeSource) { - PluralAttributeSource referencedPluralAttributeSource = (PluralAttributeSource) referencedAttributeSource; - if ( path.equals( referencedPluralAttributeSource.getMappedBy() ) ) { - oppositeAttributeName = referencedPluralAttributeSource.getName(); - } - } - } + oppositeAttributeSource = sourceIndex.locateAttributeSourceOwnedBy( + attributeBinding.getContainer().seekEntityBinding().getEntityName(), + createAttributePath( attributeBinding ) + ); } else { - oppositeAttributeName = attributeSource.getMappedBy(); + oppositeAttributeSource = + sourceIndex.attributeSource( + referencedEntityBinding.getEntityName(), + attributeSource.getMappedBy() + ); } - bindCollectionTableForeignKey( attributeBinding, attributeSource.getKeySource(), collectionTable, oppositeAttributeName ); + bindCollectionTableForeignKey( + attributeBinding, + attributeSource.getKeySource(), + collectionTable, + oppositeAttributeSource == null ? null : oppositeAttributeSource.getName() + ); } private void bindPluralAttributeIndex( @@ -3032,26 +3049,6 @@ public class Binder { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ simple instance helper methods - private void cleanupBindingContext() { - bindingContexts.pop(); - inheritanceTypes.pop(); - entityModes.pop(); - } - - public LocalBindingContext bindingContext() { - return bindingContexts.peek(); - } - - - private void setupBindingContext( - final EntityHierarchy entityHierarchy, - final RootEntitySource rootEntitySource) { - // Save inheritance type and entity mode that will apply to entire hierarchy - inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() ); - entityModes.push( rootEntitySource.getEntityMode() ); - bindingContexts.push( rootEntitySource.getLocalBindingContext() ); - } - private String propertyAccessorName(final AttributeSource attributeSource) { return propertyAccessorName( attributeSource.getPropertyAccessorName() ); } @@ -3293,78 +3290,6 @@ public class Binder { return unsavedValue; } - /** - * Apply executors to all entity hierarchies. - */ - private void applyToAllEntityHierarchies( - final LocalBindingContextExecutor executor) { - applyToAllEntityHierarchies( executor, executor ); - } - - /** - * Apply executors to all entity hierarchies. - */ - private void applyToAllEntityHierarchies( - final LocalBindingContextExecutor rootEntityExecutor, - final LocalBindingContextExecutor subEntityExecutor) { - for ( final EntityHierarchy entityHierarchy : entityHierarchiesByRootEntityName.values() ) { - applyToEntityHierarchy( entityHierarchy, rootEntityExecutor, subEntityExecutor ); - } - } - - /** - * Apply executors to a single entity hierarchy. - * - * @param entityHierarchy The entity hierarchy to be binded. - */ - private void applyToEntityHierarchy( - final EntityHierarchy entityHierarchy, - final LocalBindingContextExecutor rootEntityExecutor, - final LocalBindingContextExecutor subEntityExecutor) { - final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource(); - setupBindingContext( entityHierarchy, rootEntitySource ); - try { - LocalBindingContextExecutionContext executionContext = - new LocalBindingContextExecutionContextImpl( rootEntitySource, null ); - rootEntityExecutor.execute( executionContext ); - if ( inheritanceTypes.peek() != InheritanceType.NO_INHERITANCE ) { - applyToSubEntities( - executionContext.getEntityBinding(), - rootEntitySource, - subEntityExecutor ); - } - } - finally { - cleanupBindingContext(); - } - } - - private void applyToSubEntities( - final EntityBinding entityBinding, - final EntitySource entitySource, - final LocalBindingContextExecutor subEntityExecutor) { - for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) { - applyToSubEntity( entityBinding, subEntitySource, subEntityExecutor ); - } - } - - private void applyToSubEntity( - final EntityBinding superEntityBinding, - final EntitySource entitySource, - final LocalBindingContextExecutor subEntityExecutor) { - final LocalBindingContext bindingContext = entitySource.getLocalBindingContext(); - bindingContexts.push( bindingContext ); - try { - LocalBindingContextExecutionContext executionContext = - new LocalBindingContextExecutionContextImpl( entitySource, superEntityBinding ); - subEntityExecutor.execute( executionContext ); - applyToSubEntities( executionContext.getEntityBinding(), entitySource, subEntityExecutor ); - } - finally { - bindingContexts.pop(); - } - } - private static void addUniqueConstraintForNaturalIdColumn( final TableSpecification table, final Column column) { @@ -3372,41 +3297,6 @@ public class Binder { uniqueKey.addColumn( column ); } - private interface LocalBindingContextExecutor { - void execute(LocalBindingContextExecutionContext bindingContextContext); - } - - private interface LocalBindingContextExecutionContext { - EntitySource getEntitySource(); - EntityBinding getEntityBinding(); - EntityBinding getSuperEntityBinding(); - } - - private class LocalBindingContextExecutionContextImpl implements LocalBindingContextExecutionContext { - private final EntitySource entitySource; - private final EntityBinding superEntityBinding; - - private LocalBindingContextExecutionContextImpl( - EntitySource entitySource, - EntityBinding superEntityBinding) { - this.entitySource = entitySource; - this.superEntityBinding = superEntityBinding; - } - - @Override - public EntitySource getEntitySource() { - return entitySource; - } - @Override - public EntityBinding getEntityBinding() { - return metadata.getEntityBinding( entitySource.getEntityName() ); - } - @Override - public EntityBinding getSuperEntityBinding() { - return superEntityBinding; - } - } - public static interface DefaultNamingStrategy { String defaultName(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityHierarchyHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityHierarchyHelper.java new file mode 100644 index 0000000000..506f8b5cd1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityHierarchyHelper.java @@ -0,0 +1,183 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, 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; + +import java.util.LinkedList; + +import org.hibernate.EntityMode; +import org.hibernate.metamodel.spi.MetadataImplementor; +import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.InheritanceType; +import org.hibernate.metamodel.spi.source.EntityHierarchy; +import org.hibernate.metamodel.spi.source.EntitySource; +import org.hibernate.metamodel.spi.source.LocalBindingContext; +import org.hibernate.metamodel.spi.source.RootEntitySource; +import org.hibernate.metamodel.spi.source.SubclassEntitySource; + +/** + * @author Gail Badner + */ +public class EntityHierarchyHelper { + public interface LocalBindingContextExecutor { + void execute(LocalBindingContextExecutionContext bindingContextContext); + } + + private MetadataImplementor metadata; + + // the inheritanceTypes and entityModes correspond with bindingContexts + private final LinkedList bindingContexts = new LinkedList(); + private final LinkedList inheritanceTypes = new LinkedList(); + private final LinkedList entityModes = new LinkedList(); + + EntityHierarchyHelper(final MetadataImplementor metadata) { + this.metadata = metadata; + } + + /** + * Apply executors to all entity hierarchies. + */ + public void applyToAllEntityHierarchies( + final Iterable entityHierarchies, + final LocalBindingContextExecutor rootEntityExecutor, + final LocalBindingContextExecutor subEntityExecutor) { + for ( final EntityHierarchy entityHierarchy : entityHierarchies ) { + applyToEntityHierarchy( entityHierarchy, rootEntityExecutor, subEntityExecutor ); + } + } + + /** + * Apply executors to a single entity hierarchy. + * + * @param entityHierarchy The entity hierarchy to be binded. + */ + public void applyToEntityHierarchy( + final EntityHierarchy entityHierarchy, + final LocalBindingContextExecutor rootEntityExecutor, + final LocalBindingContextExecutor subEntityExecutor) { + bindingContexts.clear(); + inheritanceTypes.clear(); + entityModes.clear(); + final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource(); + setupBindingContext( entityHierarchy, rootEntitySource ); + try { + LocalBindingContextExecutionContext executionContext = + new LocalBindingContextExecutionContextImpl( rootEntitySource, null ); + rootEntityExecutor.execute( executionContext ); + if ( inheritanceTypes.peek() != InheritanceType.NO_INHERITANCE ) { + applyToSubEntities( + executionContext.getEntityBinding(), + rootEntitySource, + subEntityExecutor ); + } + } + finally { + cleanupBindingContext(); + } + } + + private void cleanupBindingContext() { + bindingContexts.pop(); + inheritanceTypes.pop(); + entityModes.pop(); + } + + public LocalBindingContext bindingContext() { + return bindingContexts.peek(); + } + + public InheritanceType inheritanceType() { + return inheritanceTypes.peek(); + } + + public EntityMode entityMode() { + return entityModes.peek(); + } + + private void setupBindingContext( + final EntityHierarchy entityHierarchy, + final RootEntitySource rootEntitySource) { + // Save inheritance type and entity mode that will apply to entire hierarchy + inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() ); + entityModes.push( rootEntitySource.getEntityMode() ); + bindingContexts.push( rootEntitySource.getLocalBindingContext() ); + } + + + private void applyToSubEntities( + final EntityBinding entityBinding, + final EntitySource entitySource, + final LocalBindingContextExecutor subEntityExecutor) { + for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) { + applyToSubEntity( entityBinding, subEntitySource, subEntityExecutor ); + } + } + + private void applyToSubEntity( + final EntityBinding superEntityBinding, + final EntitySource entitySource, + final LocalBindingContextExecutor subEntityExecutor) { + final LocalBindingContext bindingContext = entitySource.getLocalBindingContext(); + bindingContexts.push( bindingContext ); + try { + LocalBindingContextExecutionContext executionContext = + new LocalBindingContextExecutionContextImpl( entitySource, superEntityBinding ); + subEntityExecutor.execute( executionContext ); + applyToSubEntities( executionContext.getEntityBinding(), entitySource, subEntityExecutor ); + } + finally { + bindingContexts.pop(); + } + } + + public interface LocalBindingContextExecutionContext { + EntitySource getEntitySource(); + EntityBinding getEntityBinding(); + EntityBinding getSuperEntityBinding(); + } + + private class LocalBindingContextExecutionContextImpl implements LocalBindingContextExecutionContext { + private final EntitySource entitySource; + private final EntityBinding superEntityBinding; + + private LocalBindingContextExecutionContextImpl( + EntitySource entitySource, + EntityBinding superEntityBinding) { + this.entitySource = entitySource; + this.superEntityBinding = superEntityBinding; + } + + @Override + public EntitySource getEntitySource() { + return entitySource; + } + @Override + public EntityBinding getEntityBinding() { + return metadata.getEntityBinding( entitySource.getEntityName() ); + } + @Override + public EntityBinding getSuperEntityBinding() { + return superEntityBinding; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/SourceIndex.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/SourceIndex.java index 6c5d4c99af..035cf87d95 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/SourceIndex.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/SourceIndex.java @@ -26,10 +26,8 @@ package org.hibernate.metamodel.internal; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import org.jboss.logging.Logger; @@ -42,6 +40,7 @@ import org.hibernate.metamodel.spi.source.ComponentAttributeSource; import org.hibernate.metamodel.spi.source.EntitySource; import org.hibernate.metamodel.spi.source.IdentifierSource; import org.hibernate.metamodel.spi.source.NonAggregatedCompositeIdentifierSource; +import org.hibernate.metamodel.spi.source.PluralAttributeElementSourceResolver; import org.hibernate.metamodel.spi.source.PluralAttributeSource; import org.hibernate.metamodel.spi.source.RootEntitySource; import org.hibernate.metamodel.spi.source.SimpleIdentifierSource; @@ -59,15 +58,21 @@ public class SourceIndex { private final Map entitySourceIndexByEntityName = new HashMap(); private final Map attributeSourcesByKey = new HashMap(); + private final Map mappedByAttributeNamesByOwnerAttributeNames = + new HashMap(); public void indexEntitySource(final EntitySource entitySource) { String entityName = entitySource.getEntityName(); - EntitySourceIndex entitySourceIndex = new EntitySourceIndex( entitySource ); + EntitySourceIndex entitySourceIndex = new EntitySourceIndex( this, entitySource ); entitySourceIndexByEntityName.put( entityName, entitySourceIndex ); log.debugf( "Mapped entity source \"%s\"", entityName ); indexAttributes( entitySourceIndex ); } + public void resolveAssociationSources(String entityName) { + entitySourceIndexByEntityName.get( entityName ).resolveAssociationSources(); + } + public Map getSingularAttributeSources( String entityName, SingularAttributeSource.Nature nature) { @@ -75,10 +80,23 @@ public class SourceIndex { return entitySourceIndex.getSingularAttributeSources( nature ); } + public Map getPluralAttributeSources( + String entityName, + boolean isInverse) { + final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName ); + return entitySourceIndex.getPluralAttributeSources( isInverse ); + } + public AttributeSource attributeSource(final String entityName, final String attributePath) { return attributeSourcesByKey.get( new AttributeSourceKey( entityName, attributePath ) ); } + public AttributeSource locateAttributeSourceOwnedBy(final String entityName, final String attributePath) { + AttributeSourceKey ownerKey = new AttributeSourceKey( entityName, attributePath ); + AttributeSourceKey mappedByKey = mappedByAttributeNamesByOwnerAttributeNames.get( ownerKey ); + return mappedByKey == null ? null : attributeSourcesByKey.get( mappedByKey ); + } + public EntitySource entitySource(final String entityName) { return entitySourceIndexByEntityName.get( entityName ).entitySource; } @@ -149,6 +167,14 @@ public class SourceIndex { } } + void addMappedByAssociationByOwnerAssociation(AttributeSourceKey ownerKey, AttributeSourceKey ownedKey) { + mappedByAttributeNamesByOwnerAttributeNames.put( + ownerKey, + ownedKey + ); + + } + public static class AttributeSourceKey { private final String entityName; @@ -192,9 +218,13 @@ public class SourceIndex { containerPath + '.' + attributeName; } + public String getAttributePathQualifiedByEntityName() { + return entityName + '.' + attributePath(); + } + @Override public String toString() { - return entityName + '.' + attributePath(); + return getAttributePathQualifiedByEntityName(); } @Override @@ -231,30 +261,24 @@ public class SourceIndex { } private static class EntitySourceIndex { + private final SourceIndex sourceIndex; private final EntitySource entitySource; private final Map> identifierAttributeSourcesByNature = new HashMap>(); private final Map> singularAttributeSourcesByNature = new HashMap>(); - private final Map> pluralAttributeSourcesByNature = - new HashMap>(); + // TODO: the following should not need to be LinkedHashMap, but it appears that some unit tests + // depend on the ordering + private final Map nonInversePluralAttributeSourcesByKey = + new LinkedHashMap(); + private final Map inversePluralAttributeSourcesByKey = + new LinkedHashMap(); - private EntitySourceIndex(final EntitySource entitySource) { + private EntitySourceIndex(final SourceIndex sourceIndex, final EntitySource entitySource) { + this.sourceIndex = sourceIndex; this.entitySource = entitySource; } - private Map getSingularAttributeSources( - SingularAttributeSource.Nature nature) { - final Map entries; - if ( singularAttributeSourcesByNature.containsKey( nature ) ) { - entries = Collections.unmodifiableMap( singularAttributeSourcesByNature.get( nature ) ); - } - else { - entries = Collections.emptyMap(); - } - return entries; - } - private void indexSingularAttributeSource( String pathBase, SingularAttributeSource attributeSource, @@ -287,16 +311,28 @@ public class SourceIndex { } } - private void indexPluralAttributeSource(String pathBase, PluralAttributeSource attributeSource) { - final Set pluralAttributeSources; - if ( pluralAttributeSourcesByNature.containsKey( attributeSource.getNature() ) ) { - pluralAttributeSources = pluralAttributeSourcesByNature.get( attributeSource.getNature() ); + private Map getSingularAttributeSources( + SingularAttributeSource.Nature nature) { + final Map entries; + if ( singularAttributeSourcesByNature.containsKey( nature ) ) { + entries = Collections.unmodifiableMap( singularAttributeSourcesByNature.get( nature ) ); } else { - pluralAttributeSources = new LinkedHashSet(); - pluralAttributeSourcesByNature.put( attributeSource.getNature(), pluralAttributeSources ); + entries = Collections.emptyMap(); } - if ( !pluralAttributeSources.add( attributeSource ) ) { + return entries; + } + + private void indexPluralAttributeSource( + String pathBase, + PluralAttributeSource attributeSource) { + AttributeSourceKey key = + new AttributeSourceKey( entitySource.getEntityName(), pathBase, attributeSource.getName() ); + final Map map = + attributeSource.isInverse() ? + inversePluralAttributeSourcesByKey : + nonInversePluralAttributeSourcesByKey; + if ( map.put( key, attributeSource ) != null ) { throw new AssertionFailure( String.format( "Attempt to reindex attribute source for: [%s]", @@ -305,5 +341,37 @@ public class SourceIndex { ); } } + + private Map getPluralAttributeSources( + boolean isInverse) { + final Map map = + isInverse ? + inversePluralAttributeSourcesByKey : + nonInversePluralAttributeSourcesByKey; + return Collections.unmodifiableMap( map ); + } + + private void resolveAssociationSources() { + for ( Map.Entry entry : inversePluralAttributeSourcesByKey.entrySet() ) { + final AttributeSourceKey pluralAttributeSourceKey = entry.getKey(); + final PluralAttributeSource pluralAttributeSource = entry.getValue(); + if ( pluralAttributeSource.getMappedBy() != null ) { + pluralAttributeSource.resolvePluralAttributeElementSource( + new PluralAttributeElementSourceResolver.PluralAttributeElementSourceResolutionContext() { + @Override + public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) { + AttributeSourceKey ownerAttributeSourceKey = new AttributeSourceKey( referencedEntityName, mappedBy ); + AttributeSource ownerAttributeSource = sourceIndex.attributeSource( referencedEntityName, mappedBy ); + sourceIndex.addMappedByAssociationByOwnerAssociation( + ownerAttributeSourceKey, + pluralAttributeSourceKey + ); + return ownerAttributeSource; + } + } + ); + } + } + } } }