From 85e2d484318fc5360578bd5ad1398ae253ae8b65 Mon Sep 17 00:00:00 2001 From: John Verhaeg Date: Thu, 1 Mar 2012 09:28:50 -0600 Subject: [PATCH] HHH-7048: Finished changes to ensure resolution of all entities and types during binding. Refactored quite a bit of code while I did this, addressing some TODOs such as using consistent method names and cleaning up redundant and duplicate code. Still have some cleanup to do regarding the break out of the HibernateTypeHelper class. Also removed some large blocks of unused code, so this may need to be added back in if it's to be used in the future. --- .../metamodel/internal/MetadataImpl.java | 4 +- .../metamodel/internal/source/Binder.java | 2346 +++++++---------- .../internal/source/HibernateTypeHelper.java | 25 +- 3 files changed, 946 insertions(+), 1429 deletions(-) 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 6a84daea5897..980b25b91172 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 @@ -238,9 +238,9 @@ private void processIdentifierGenerators(MetadataSourceProcessor[] metadataSourc } private void processMappings(MetadataSourceProcessor[] metadataSourceProcessors) { - final Binder binder = new Binder( this ); + final Binder binder = new Binder( this, identifierGeneratorFactory ); for ( MetadataSourceProcessor processor : metadataSourceProcessors ) - binder.processEntityHierarchies( processor.extractEntityHierarchies() ); + binder.bindEntities( processor.extractEntityHierarchies() ); } private void bindMappingDependentMetadata(MetadataSourceProcessor[] metadataSourceProcessors) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java index f993463506e7..741c00866e9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java @@ -23,17 +23,13 @@ */ package org.hibernate.metamodel.internal.source; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Comparator; -import java.util.Deque; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; - -import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.TruthValue; import org.hibernate.cfg.AvailableSettings; @@ -42,8 +38,9 @@ import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PersistentIdentifierGenerator; +import org.hibernate.id.factory.IdentifierGeneratorFactory; +import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; -import org.hibernate.metamodel.internal.source.hbm.Helper; import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBindingContainer; @@ -52,6 +49,8 @@ import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityDiscriminator; +import org.hibernate.metamodel.spi.binding.EntityVersion; +import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.spi.binding.IdGenerator; import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding; @@ -60,18 +59,19 @@ import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.SecondaryTable; import org.hibernate.metamodel.spi.binding.SetBinding; -import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; +import org.hibernate.metamodel.spi.binding.TypeDefinition; import org.hibernate.metamodel.spi.domain.Attribute; import org.hibernate.metamodel.spi.domain.Composite; import org.hibernate.metamodel.spi.domain.Entity; import org.hibernate.metamodel.spi.domain.PluralAttribute; import org.hibernate.metamodel.spi.domain.SingularAttribute; +import org.hibernate.metamodel.spi.relational.AbstractValue; 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.InLineView; +import org.hibernate.metamodel.spi.relational.JdbcDataType; import org.hibernate.metamodel.spi.relational.PrimaryKey; import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Table; @@ -81,7 +81,6 @@ import org.hibernate.metamodel.spi.source.AttributeSource; import org.hibernate.metamodel.spi.source.AttributeSourceContainer; import org.hibernate.metamodel.spi.source.BasicPluralAttributeElementSource; -import org.hibernate.metamodel.spi.source.ColumnBindingDefaults; import org.hibernate.metamodel.spi.source.ColumnSource; import org.hibernate.metamodel.spi.source.ComponentAttributeSource; import org.hibernate.metamodel.spi.source.ConstraintSource; @@ -89,8 +88,12 @@ import org.hibernate.metamodel.spi.source.DiscriminatorSource; import org.hibernate.metamodel.spi.source.EntityHierarchy; import org.hibernate.metamodel.spi.source.EntitySource; +import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource; +import org.hibernate.metamodel.spi.source.IdentifierSource; +import org.hibernate.metamodel.spi.source.IdentifierSource.Nature; import org.hibernate.metamodel.spi.source.InLineViewSource; import org.hibernate.metamodel.spi.source.LocalBindingContext; +import org.hibernate.metamodel.spi.source.MappingDefaults; import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MetaAttributeContext; import org.hibernate.metamodel.spi.source.MetaAttributeSource; @@ -109,7 +112,6 @@ import org.hibernate.metamodel.spi.source.SingularAttributeNature; import org.hibernate.metamodel.spi.source.SingularAttributeSource; import org.hibernate.metamodel.spi.source.Sortable; -import org.hibernate.metamodel.spi.source.SubclassEntityContainer; import org.hibernate.metamodel.spi.source.SubclassEntitySource; import org.hibernate.metamodel.spi.source.TableSource; import org.hibernate.metamodel.spi.source.TableSpecificationSource; @@ -125,1590 +127,1106 @@ /** * The common binder shared between annotations and {@code hbm.xml} processing. *

- * The API consists of {@link #Binder( MetadataImplementor )} and {@link #processEntityHierarchies(Iterable)} - * - * @todo Really need to chop this up. The class is doing so many different things right now. - * @todo And really need to come up with consistent method naming. - * @todo This class really should live in the o.h.metamodel.internal package + * The API consists of {@link #Binder(MetadataImplementor, IdentifierGeneratorFactory)} and {@link #bindEntities(Iterable)} * * @author Steve Ebersole * @author Hardy Ferentschik * @author Gail Badner */ +// todo: move to parent package +// todo: chase unresolved attribute references public class Binder { + private final MetadataImplementor metadata; - private final ArrayList processedEntityNames = new ArrayList(); + private final IdentifierGeneratorFactory identifierGeneratorFactory; + private final ObjectNameNormalizer nameNormalizer; + private final HashMap< String, EntitySource > entitySourcesByName = new HashMap< String, EntitySource >(); + private final HashMap< RootEntitySource, EntityHierarchy > entityHierarchiesByRootEntitySource = + new HashMap< RootEntitySource, EntityHierarchy >(); + private final HashMap< String, AttributeSource > attributeSourcesByName = new HashMap< String, AttributeSource >(); + private final LinkedList< LocalBindingContext > bindingContexts = new LinkedList< LocalBindingContext >(); + private final LinkedList< InheritanceType > inheritanceTypes = new LinkedList< InheritanceType >(); + private final LinkedList< EntityMode > entityModes = new LinkedList< EntityMode >(); + + private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class + + public Binder( final MetadataImplementor metadata, + final IdentifierGeneratorFactory identifierGeneratorFactory ) { + this.metadata = metadata; + this.identifierGeneratorFactory = identifierGeneratorFactory; + nameNormalizer = new ObjectNameNormalizer() { - private HibernateTypeHelper typeHelper = new HibernateTypeHelper( this ); + @Override + protected NamingStrategy getNamingStrategy() { + return metadata.getNamingStrategy(); + } - private final ObjectNameNormalizer NAME_NORMALIZER = new ObjectNameNormalizer() { - @Override - protected boolean isUseQuotedIdentifiersGlobally() { - return metadata.isGloballyQuotedIdentifiers(); - } + @Override + protected boolean isUseQuotedIdentifiersGlobally() { + return metadata.isGloballyQuotedIdentifiers(); + } + }; + typeHelper = new HibernateTypeHelper( this, metadata ); + } - @Override - protected NamingStrategy getNamingStrategy() { - return metadata.getNamingStrategy(); + private AttributeBinding bindAttribute( final AttributeBindingContainer attributeBindingContainer, + final AttributeSource attributeSource ) { + // Return existing binding if available + final String attributeName = attributeSource.getName(); + System.out.println( "bindAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " )" ); + final AttributeBinding attributeBinding = attributeBindingContainer.locateAttributeBinding( attributeName ); + if ( attributeBinding != null ) { + return attributeBinding; } - }; - - private InheritanceType currentInheritanceType; - private EntityMode currentHierarchyEntityMode; - private LocalBindingContext currentBindingContext; - private HashMap sourcesByName = new HashMap(); - - public Binder( MetadataImplementor metadata ) { - this.metadata = metadata; + if ( attributeSource.isSingular() ) { + return bindSingularAttribute( attributeBindingContainer, ( SingularAttributeSource ) attributeSource ); + } + return bindPluralAttribute( attributeBindingContainer, ( PluralAttributeSource ) attributeSource ); } - MetadataImplementor getMetadata() { - return metadata; + private void bindAttributes( final AttributeBindingContainer attributeBindingContainer, + final AttributeSourceContainer attributeSourceContainer ) { + System.out.println( "bindAttributes( " + attributeBindingContainer.getAttributeContainer().getName() + " )" ); + for ( final AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) { + bindAttribute( attributeBindingContainer, attributeSource ); + } } - LocalBindingContext getCurrentBindingContext() { - return currentBindingContext; + private AbstractPluralAttributeBinding bindBagAttribute( final AttributeBindingContainer attributeBindingContainer, + final PluralAttributeSource attributeSource, + PluralAttribute attribute ) { + if ( attribute == null ) { + attribute = attributeBindingContainer.getAttributeContainer().createBag( attributeSource.getName() ); + } + return attributeBindingContainer.makeBagAttributeBinding( attribute, + pluralAttributeElementNature( attributeSource ), + pluralAttributeKeyBinding( attributeBindingContainer, + attributeSource ), + propertyAccessorName( attributeSource ), + attributeSource.isIncludedInOptimisticLocking(), + false, + createMetaAttributeContext( attributeBindingContainer, + attributeSource ) ); } - /** - * Process an entity hierarchy. - * - * @param entityHierarchies THe hierarchies to process. - */ - public void processEntityHierarchies( Iterable entityHierarchies ) { - // Index sources by name so we can find and resolve entities on the fly as references to them - // are encountered (e.g., within associations) - for ( EntityHierarchy hierarchy : entityHierarchies ) { - mapSourcesByName( hierarchy.getRootEntitySource() ); - } - - for ( EntityHierarchy hierarchy : entityHierarchies ) { - processEntityHierarchy( hierarchy ); - } - } + private BasicAttributeBinding bindBasicAttribute( final AttributeBindingContainer attributeBindingContainer, + final SingularAttributeSource attributeSource, + SingularAttribute attribute ) { - private void mapSourcesByName(EntitySource source) { - sourcesByName.put( source.getEntityName(), source ); - for ( SubclassEntitySource subclassEntitySource : source.subclassEntitySources() ) { - mapSourcesByName( subclassEntitySource ); - } + System.out.println( "bindBasicAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " )" ); + if ( attribute == null ) { + attribute = createSingularAttribute( attributeBindingContainer, attributeSource ); + } + final List< RelationalValueBinding > relationalValueBindings = + bindValues( attributeBindingContainer, + attributeSource, + attribute, + attributeBindingContainer.seekEntityBinding().getPrimaryTable() ); + final BasicAttributeBinding attributeBinding = + attributeBindingContainer.makeBasicAttributeBinding( attribute, + relationalValueBindings, + propertyAccessorName( attributeSource ), + attributeSource.isIncludedInOptimisticLocking(), + attributeSource.isLazy(), + createMetaAttributeContext( attributeBindingContainer, + attributeSource ), + attributeSource.getGeneration() ); + bindHibernateTypeDescriptor( attributeBinding.getHibernateTypeDescriptor(), + attributeSource.getTypeInformation(), + attributeBinding.getAttribute(), + ( AbstractValue ) relationalValueBindings.get( 0 ).getValue() ); + final HibernateTypeDescriptor hibernateTypeDescriptor = attributeBinding.getHibernateTypeDescriptor(); + attributeBinding.getAttribute().resolveType( bindingContexts.peek(). + makeJavaType( hibernateTypeDescriptor.getJavaTypeName() ) ); + return attributeBinding; } - @SuppressWarnings( {"unchecked"}) - private void processEntityHierarchy(EntityHierarchy hierarchy) { - final RootEntitySource rootEntitySource = hierarchy.getRootEntitySource(); - currentInheritanceType = hierarchy.getHierarchyInheritanceType(); - currentHierarchyEntityMode = rootEntitySource.getEntityMode(); - try { - // create the binding - final EntityBinding rootEntityBinding = createEntityBinding( rootEntitySource, null ); - - // Create identifier generator for root entity - Properties properties = new Properties(); - properties.putAll( metadata.getServiceRegistry().getService( ConfigurationService.class ).getSettings() ); - if ( !properties.contains( AvailableSettings.PREFER_POOLED_VALUES_LO ) ) { - properties.put( AvailableSettings.PREFER_POOLED_VALUES_LO, "false" ); - } - if ( !properties.contains( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER ) ) { - properties.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, NAME_NORMALIZER ); - } - rootEntityBinding.getHierarchyDetails() - .getEntityIdentifier() - .createIdentifierGenerator( metadata.getIdentifierGeneratorFactory(), properties ); + private void bindBasicElementSetTablePrimaryKey( final SetBinding attributeBinding ) { - if ( currentInheritanceType != InheritanceType.NO_INHERITANCE ) { - processHierarchySubEntities( rootEntitySource, rootEntityBinding ); + final PrimaryKey primaryKey = attributeBinding.getCollectionTable().getPrimaryKey(); + final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey(); + final BasicPluralAttributeElementBinding elementBinding = + ( BasicPluralAttributeElementBinding ) attributeBinding.getPluralAttributeElementBinding(); + if ( elementBinding.getPluralAttributeElementNature() != PluralAttributeElementNature.BASIC ) { + throw new MappingException( + String.format( "Expected a SetBinding with an element of nature PluralAttributeElementNature.BASIC; instead was %s", + elementBinding.getPluralAttributeElementNature() ), + bindingContexts.peek().getOrigin() ); + } + for ( final Column foreignKeyColumn : foreignKey.getSourceColumns() ) { + primaryKey.addColumn( foreignKeyColumn ); + } + for ( final RelationalValueBinding elementValueBinding : elementBinding.getRelationalValueBindings() ) { + if ( elementValueBinding.getValue() instanceof Column && !elementValueBinding.isNullable() ) { + primaryKey.addColumn( ( Column ) elementValueBinding.getValue() ); } } - finally { - currentHierarchyEntityMode = null; - currentInheritanceType = null; + if ( primaryKey.getColumnSpan() == foreignKey.getColumnSpan() ) { + // for backward compatibility, allow a set with no not-null + // element columns, using all columns in the row locater SQL + // todo: create an implicit not null constraint on all cols? } } - private void processHierarchySubEntities( - SubclassEntityContainer subclassEntitySource, - EntityBinding superEntityBinding) { - for ( SubclassEntitySource subEntity : subclassEntitySource.subclassEntitySources() ) { - // create the current entity's binding.... - final EntityBinding entityBinding = createEntityBinding( subEntity, superEntityBinding ); - // then drill down into its sub-class entities - processHierarchySubEntities( subEntity, entityBinding ); - } + private void bindBasicPluralElementRelationalValues( final RelationalValueSourceContainer relationalValueSourceContainer, + final BasicPluralAttributeElementBinding elementBinding ) { + elementBinding.setRelationalValueBindings( bindValues( elementBinding.getPluralAttributeBinding().getContainer(), + relationalValueSourceContainer, + elementBinding.getPluralAttributeBinding().getAttribute(), + elementBinding.getPluralAttributeBinding().getCollectionTable() ) ); } - - // Entities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - private EntityBinding createEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) { - if ( processedEntityNames.contains( entitySource.getEntityName() ) ) { - return metadata.getEntityBinding( entitySource.getEntityName() ); + private void bindCollectionElement( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeSource attributeSource ) { + final PluralAttributeElementSource elementSource = attributeSource.getElementSource(); + if ( elementSource.getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.BASIC ) { + final BasicPluralAttributeElementSource basicElementSource = ( BasicPluralAttributeElementSource ) elementSource; + final BasicPluralAttributeElementBinding basicCollectionElement = + ( BasicPluralAttributeElementBinding ) attributeBinding.getPluralAttributeElementBinding(); + bindBasicPluralElementRelationalValues( basicElementSource, basicCollectionElement ); + return; } + // todo : handle cascades + // final Cascadeable cascadeable = (Cascadeable) binding.getPluralAttributeElementBinding(); + // cascadeable.setCascadeStyles( source.getCascadeStyles() ); + // todo : implement + throw new NotYetImplementedException( String.format( "Support for collection elements of type %s not yet implemented", + elementSource.getNature() ) ); + } - currentBindingContext = entitySource.getLocalBindingContext(); - try { - final EntityBinding entityBinding = doCreateEntityBinding( entitySource, superEntityBinding ); - - metadata.addEntity( entityBinding ); - processedEntityNames.add( entityBinding.getEntity().getName() ); - - processFetchProfiles( entitySource, entityBinding ); - - return entityBinding; - } - finally { - currentBindingContext = null; + private void bindCollectionIndex( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeSource attributeSource ) { + if ( attributeSource.getPluralAttributeNature() != PluralAttributeNature.LIST + && attributeSource.getPluralAttributeNature() != PluralAttributeNature.MAP ) { + return; } + // todo : implement + throw new NotYetImplementedException(); } - private EntityBinding doCreateEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) { - final EntityBinding entityBinding = createBasicEntityBinding( entitySource, superEntityBinding ); - - bindSecondaryTables( entitySource, entityBinding ); - - Deque tableStack = new ArrayDeque( ); - tableStack.add( entityBinding.getPrimaryTable() ); - bindAttributes( entitySource, entityBinding, tableStack ); - - bindTableUniqueConstraints( entitySource, entityBinding ); - - return entityBinding; + private void bindCollectionKey( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeSource attributeSource ) { + final PluralAttributeKeySource keySource = attributeSource.getKeySource(); + final String foreignKeyName = + StringHelper.isEmpty( keySource.getExplicitForeignKeyName() ) + ? null // todo: is null FK name allowed (is there a default?) + : quotedIdentifier( keySource.getExplicitForeignKeyName() ); + final TableSpecification table = attributeBinding.getContainer().seekEntityBinding().getPrimaryTable(); + attributeBinding.getPluralAttributeKeyBinding().prepareForeignKey( foreignKeyName, table ); + attributeBinding.getPluralAttributeKeyBinding().getForeignKey().setDeleteRule( keySource.getOnDeleteAction() ); + if ( keySource.getReferencedEntityAttributeName() == null ) { + bindCollectionKeyTargetingPrimaryKey( attributeBinding, attributeSource.getKeySource() ); + } else { + bindCollectionKeyTargetingPropertyRef( attributeBinding, attributeSource.getKeySource() ); + } } - private EntityBinding createBasicEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) { - if ( superEntityBinding == null ) { - return makeRootEntityBinding( (RootEntitySource) entitySource ); - } - else { - switch ( currentInheritanceType ) { - case SINGLE_TABLE: - return makeDiscriminatedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding ); - case JOINED: - return makeJoinedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding ); - case TABLE_PER_CLASS: - return makeUnionedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding ); - default: - // extreme internal error! - throw new AssertionFailure( "Internal condition failure" ); + private void bindCollectionKeyTargetingPrimaryKey( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeKeySource keySource ) { + for ( final RelationalValueSource valueSource : keySource.getValueSources() ) { + if ( valueSource instanceof ColumnSource ) { + final Column column = createColumn( attributeBinding.getCollectionTable(), + ( ColumnSource ) valueSource, + attributeBinding.getAttribute().getName(), + false, + true ); + attributeBinding.getPluralAttributeKeyBinding().getForeignKey().addColumn( column ); + } else { + // todo: deal with formulas??? } } } - private EntityBinding makeRootEntityBinding(RootEntitySource entitySource) { - final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, null ); - - bindPrimaryTable( entitySource, entityBinding ); - - bindIdentifier( entitySource, entityBinding ); - bindVersion( entityBinding, entitySource ); - bindDiscriminator( entitySource, entityBinding ); - - entityBinding.getHierarchyDetails().setCaching( entitySource.getCaching() ); - entityBinding.getHierarchyDetails().setExplicitPolymorphism( entitySource.isExplicitPolymorphism() ); - entityBinding.getHierarchyDetails().setOptimisticLockStyle( entitySource.getOptimisticLockStyle() ); - - entityBinding.setMutable( entitySource.isMutable() ); - entityBinding.setWhereFilter( entitySource.getWhere() ); - entityBinding.setRowId( entitySource.getRowId() ); - - return entityBinding; - } - - private EntityBinding buildBasicEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) { - final EntityBinding entityBinding = superEntityBinding == null - ? new EntityBinding( currentInheritanceType, currentHierarchyEntityMode ) - : new EntityBinding( superEntityBinding ); - - final String entityName = entitySource.getEntityName(); - final String className = currentHierarchyEntityMode == EntityMode.POJO ? entitySource.getClassName() : null; - - final Entity entity = new Entity( - entityName, - className, - currentBindingContext.makeClassReference( className ), - superEntityBinding == null ? null : superEntityBinding.getEntity() - ); - entityBinding.setEntity( entity ); - - entityBinding.setJpaEntityName( entitySource.getJpaEntityName() ); - - if ( currentHierarchyEntityMode == EntityMode.POJO ) { - final String proxy = entitySource.getProxy(); - if ( proxy != null ) { - entityBinding.setProxyInterfaceType( - currentBindingContext.makeClassReference( - currentBindingContext.qualifyClassName( proxy ) - ) - ); - entityBinding.setLazy( true ); + private void bindCollectionKeyTargetingPropertyRef( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeKeySource keySource ) { + final EntityBinding ownerEntityBinding = attributeBinding.getContainer().seekEntityBinding(); + final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding( + keySource.getReferencedEntityAttributeName() + ); + final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey(); + if ( !referencedAttributeBinding.getAttribute().isSingular() ) { + throw new MappingException( + String.format( "Collection (%s) property-ref is a plural attribute (%s); must be singular.", + attributeBinding.getAttribute().getRole(), + referencedAttributeBinding ), + bindingContexts.peek().getOrigin() ); + } + final Iterator< RelationalValueBinding > targetValueBindings = + ( ( SingularAttributeBinding ) referencedAttributeBinding ).getRelationalValueBindings().iterator(); + for ( final RelationalValueSource valueSource : keySource.getValueSources() ) { + if ( !targetValueBindings.hasNext() ) { + throw new MappingException( + String.format( "More collection key source columns than target columns for collection: %s", + attributeBinding.getAttribute().getRole() ), + bindingContexts.peek().getOrigin() ); } - else if ( entitySource.isLazy() ) { - entityBinding.setProxyInterfaceType( entityBinding.getEntity().getClassReferenceUnresolved() ); - entityBinding.setLazy( true ); + final Value targetValue = targetValueBindings.next().getValue(); + if ( ColumnSource.class.isInstance( valueSource ) ) { + final ColumnSource columnSource = ( ColumnSource ) valueSource; + final Column column = createColumn( attributeBinding.getCollectionTable(), + columnSource, + attributeBinding.getAttribute().getName(), + false, + true ); + if ( targetValue != null && !( targetValue instanceof Column ) ) { + throw new MappingException( + String.format( "Type mismatch between collection key source and target; collection: %s; source column (%s) corresponds with target derived value (%s).", + attributeBinding.getAttribute().getRole(), + columnSource.getName(), + ( ( DerivedValue ) targetValue ).getExpression() ), + bindingContexts.peek().getOrigin() ); + } + foreignKey.addColumnMapping( column, ( Column ) targetValue ); + } else { + // todo: deal with formulas??? } } - else { - entityBinding.setProxyInterfaceType( null ); - entityBinding.setLazy( entitySource.isLazy() ); - } - - final String customTuplizerClassName = entitySource.getCustomTuplizerClassName(); - if ( customTuplizerClassName != null ) { - entityBinding.setCustomEntityTuplizerClass( - currentBindingContext.locateClassByName( - customTuplizerClassName - ) - ); - } - - final String customPersisterClassName = entitySource.getCustomPersisterClassName(); - if ( customPersisterClassName != null ) { - entityBinding.setCustomEntityPersisterClass( - currentBindingContext.locateClassByName( - customPersisterClassName - ) - ); - } - - entityBinding.setMetaAttributeContext( buildMetaAttributeContext( entitySource ) ); - - entityBinding.setDynamicUpdate( entitySource.isDynamicUpdate() ); - entityBinding.setDynamicInsert( entitySource.isDynamicInsert() ); - entityBinding.setBatchSize( entitySource.getBatchSize() ); - entityBinding.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() ); - entityBinding.setAbstract( entitySource.isAbstract() ); - - entityBinding.setCustomLoaderName( entitySource.getCustomLoaderName() ); - entityBinding.setCustomInsert( entitySource.getCustomSqlInsert() ); - entityBinding.setCustomUpdate( entitySource.getCustomSqlUpdate() ); - entityBinding.setCustomDelete( entitySource.getCustomSqlDelete() ); - - if ( entitySource.getSynchronizedTableNames() != null ) { - entityBinding.addSynchronizedTableNames( entitySource.getSynchronizedTableNames() ); + if ( targetValueBindings != null && targetValueBindings.hasNext() ) { + throw new MappingException( String.format( "More collection key target columns than source columns for collection: %s", + attributeBinding.getAttribute().getRole() ), + bindingContexts.peek().getOrigin() ); } - - entityBinding.setJpaCallbackClasses(entitySource.getJpaCallbackClasses()); - - return entityBinding; } - private EntityBinding makeDiscriminatedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) { - final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding ); - - entityBinding.setPrimaryTable( superEntityBinding.getPrimaryTable() ); - entityBinding.setPrimaryTableName( superEntityBinding.getPrimaryTableName() ); - bindDiscriminatorValue( entitySource, entityBinding ); - - return entityBinding; - } - - private EntityBinding makeJoinedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) { - final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding ); - - bindPrimaryTable( entitySource, entityBinding ); - - // todo : join - - return entityBinding; - } - - private EntityBinding makeUnionedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) { - final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding ); - - bindPrimaryTable( entitySource, entityBinding ); - - // todo : ?? - - return entityBinding; - } - - // Attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - private void bindIdentifier(RootEntitySource entitySource, EntityBinding entityBinding) { - if ( entitySource.getIdentifierSource() == null ) { - throw new AssertionFailure( "Expecting identifier information on root entity descriptor" ); + private void bindCollectionTable( final AbstractPluralAttributeBinding pluralAttributeBinding, + final PluralAttributeSource attributeSource ) { + if ( attributeSource.getElementSource().getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.ONE_TO_MANY ) { + return; } - switch ( entitySource.getIdentifierSource().getNature() ) { - case SIMPLE: { - bindSimpleIdentifier( (SimpleIdentifierSource) entitySource.getIdentifierSource(), entityBinding ); - break; - } - case AGGREGATED_COMPOSITE: { - // composite id with an actual component class - break; - } - case COMPOSITE: { - // what we used to term an "embedded composite identifier", which is not tobe confused with the JPA - // term embedded. Specifically a composite id where there is no component class, though there may - // be a @IdClass :/ - break; + final DefaultNamingStrategy defaultNamingStategy = new DefaultNamingStrategy() { + + @Override + public String defaultName() { + final AttributeBindingContainer attributeBindingContainer = pluralAttributeBinding.getContainer(); + final EntityBinding owner = attributeBindingContainer.seekEntityBinding(); + final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() ) + ? ( ( Table ) owner.getPrimaryTable() ).getTableName().getName() + : null; + return bindingContexts.peek().getNamingStrategy().collectionTableName( owner.getEntity().getName(), + ownerTableLogicalName, + null, // todo: here + null, // todo: and here + attributeBindingContainer.getPathBase() + + '.' + attributeSource.getName() ); } + }; + pluralAttributeBinding.setCollectionTable( createTable( attributeSource.getCollectionTableSpecificationSource(), + defaultNamingStategy ) ); + if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableComment() ) ) { + pluralAttributeBinding.getCollectionTable().addComment( attributeSource.getCollectionTableComment() ); } - } - - private void bindSimpleIdentifier( - SimpleIdentifierSource identifierSource, - EntityBinding entityBinding) { - final BasicAttributeBinding idAttributeBinding = bindBasicAttribute( - identifierSource.getIdentifierAttributeSource(), - entityBinding - ); - - entityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding ); - IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor(); - if ( generator == null ) { - Map params = new HashMap(); - params.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() ); - generator = new IdGenerator( "default_assign_identity_generator", "assigned", params ); + if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) { + pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() ); } - entityBinding.getHierarchyDetails() - .getEntityIdentifier() - .setIdGenerator( generator ); - - final List relationalValueBindings = idAttributeBinding.getRelationalValueBindings(); + } - if ( relationalValueBindings.size() == 1 ) { - final Value value = relationalValueBindings.get( 0 ).getValue(); - if ( !Column.class.isInstance( value ) ) { - // this should never ever happen.. - throw new AssertionFailure( "Simple-id was not a column." ); - } - entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( value ) ); + private void bindCollectionTablePrimaryKey( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeSource attributeSource ) { + if ( attributeSource.getElementSource().getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.ONE_TO_MANY + || attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) { + return; } - else { - for ( RelationalValueBinding valueBinding : relationalValueBindings ) { - final Value value = valueBinding.getValue(); - if ( Column.class.isInstance( value ) ) { - entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( value ) ); - } + if ( attributeBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.BASIC ) { + if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SET ) { + bindBasicElementSetTablePrimaryKey( ( SetBinding ) attributeBinding ); + } else { + throw new NotYetImplementedException( "Only Sets with basic elements are supported so far." ); } } } - private void bindVersion(EntityBinding entityBinding, RootEntitySource entitySource) { - final VersionAttributeSource versioningAttributeSource = entitySource.getVersioningAttributeSource(); - if ( versioningAttributeSource == null ) { - return; - } - - BasicAttributeBinding attributeBinding = bindBasicAttribute( versioningAttributeSource, entityBinding ); - entityBinding.getHierarchyDetails().getEntityVersion().setVersioningAttributeBinding( attributeBinding ); - entityBinding.getHierarchyDetails().getEntityVersion().setUnsavedValue( versioningAttributeSource.getUnsavedValue() ); + private CompositeAttributeBinding bindComponentAttribute( final AttributeBindingContainer attributeBindingContainer, + final ComponentAttributeSource attributeSource, + SingularAttribute attribute ) { + System.out.println( "bindComponentAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " )" ); + Composite composite; + if ( attribute == null ) { + composite = new Composite( attributeSource.getPath(), attributeSource.getClassName(), + attributeSource.getClassReference(), null ); + attribute = attributeBindingContainer.getAttributeContainer().createCompositeAttribute( attributeSource.getName(), + composite ); + } else { + composite = ( Composite ) attribute.getSingularAttributeType(); + } + final SingularAttribute referencingAttribute; + if ( StringHelper.isEmpty( attributeSource.getParentReferenceAttributeName() ) ) { + referencingAttribute = null; + } else { + referencingAttribute = composite.createSingularAttribute( attributeSource.getParentReferenceAttributeName() ); + } + final CompositeAttributeBinding attributeBinding = + attributeBindingContainer.makeComponentAttributeBinding( attribute, + referencingAttribute, + propertyAccessorName( attributeSource ), + attributeSource.isIncludedInOptimisticLocking(), + attributeSource.isLazy(), + createMetaAttributeContext( attributeBindingContainer, + attributeSource ) ); + bindAttributes( attributeBinding, attributeSource ); + return attributeBinding; } - public static final ColumnBindingDefaults DISCRIMINATOR_COLUMN_BINDING_DEFAULTS = new ColumnBindingDefaults() { - @Override - public boolean areValuesIncludedInInsertByDefault() { - return true; - } - - @Override - public boolean areValuesIncludedInUpdateByDefault() { - return false; - } - - @Override - public boolean areValuesNullableByDefault() { - return false; - } - }; - - private void bindDiscriminator(RootEntitySource entitySource, EntityBinding entityBinding) { - final DiscriminatorSource discriminatorSource = entitySource.getDiscriminatorSource(); + private void bindDiscriminator( final EntityBinding rootEntityBinding, + final RootEntitySource rootEntitySource ) { + final DiscriminatorSource discriminatorSource = rootEntitySource.getDiscriminatorSource(); if ( discriminatorSource == null ) { return; } + final RelationalValueSource valueSource = discriminatorSource.getDiscriminatorRelationalValueSource(); + final TableSpecification table = rootEntityBinding.locateTable( valueSource.getContainingTableName() ); + AbstractValue value; + if ( valueSource instanceof ColumnSource ) { + value = createColumn( table, + ( ColumnSource ) valueSource, + bindingContexts.peek().getMappingDefaults().getDiscriminatorColumnName(), + false, + false ); + } else { + value = table.locateOrCreateDerivedValue( ( ( DerivedValueSource ) valueSource ).getExpression() ); + } + final EntityDiscriminator discriminator = new EntityDiscriminator( value, discriminatorSource.isInserted(), + discriminatorSource.isForced() ); + rootEntityBinding.getHierarchyDetails().setEntityDiscriminator( discriminator ); + rootEntityBinding.setDiscriminatorMatchValue( rootEntitySource.getDiscriminatorMatchValue() ); + // Configure discriminator hibernate type + final String typeName = discriminatorSource.getExplicitHibernateTypeName() != null + ? discriminatorSource.getExplicitHibernateTypeName() + : "string"; + final HibernateTypeDescriptor hibernateTypeDescriptor = discriminator.getExplicitHibernateTypeDescriptor(); + hibernateTypeDescriptor.setExplicitTypeName( typeName ); + resolveHibernateResolvedType( hibernateTypeDescriptor, typeName, value ); + } - TableSpecification table = entityBinding.locateTable( discriminatorSource.getDiscriminatorRelationalValueSource().getContainingTableName() ); - Value relationalValue; - if ( ColumnSource.class.isInstance( discriminatorSource.getDiscriminatorRelationalValueSource() ) ) { - relationalValue = makeColumn( - ( ColumnSource) discriminatorSource.getDiscriminatorRelationalValueSource(), - DISCRIMINATOR_COLUMN_BINDING_DEFAULTS, - table, - currentBindingContext.getMappingDefaults().getDiscriminatorColumnName(), - false - ); - } - else { - relationalValue = makeDerivedValue( (DerivedValueSource) discriminatorSource.getDiscriminatorRelationalValueSource(), table ); + private EntityBinding bindEntities( final EntityHierarchy entityHierarchy ) { + final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource(); + System.out.println( "bindEntities(): rootEntitySource = " + rootEntitySource.getEntityName() ); + // Return existing binding if available + EntityBinding rootEntityBinding = metadata.getEntityBinding( rootEntitySource.getEntityName() ); + if ( rootEntityBinding != null ) { + return rootEntityBinding; + } + // Save inheritance type and entity mode that will apply to entire hierarchy + inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() ); + entityModes.push( rootEntitySource.getEntityMode() ); + try { + // Create root entity binding + rootEntityBinding = createEntityBinding( rootEntitySource, null ); + // Create/Bind root-specific information + bindIdentifier( rootEntityBinding, rootEntitySource.getIdentifierSource() ); + bindVersion( rootEntityBinding, rootEntitySource.getVersioningAttributeSource() ); + bindDiscriminator( rootEntityBinding, rootEntitySource ); + createIdentifierGenerator( rootEntityBinding ); + rootEntityBinding.getHierarchyDetails().setCaching( rootEntitySource.getCaching() ); + rootEntityBinding.getHierarchyDetails().setExplicitPolymorphism( rootEntitySource.isExplicitPolymorphism() ); + rootEntityBinding.getHierarchyDetails().setOptimisticLockStyle( rootEntitySource.getOptimisticLockStyle() ); + rootEntityBinding.setMutable( rootEntitySource.isMutable() ); + rootEntityBinding.setWhereFilter( rootEntitySource.getWhere() ); + rootEntityBinding.setRowId( rootEntitySource.getRowId() ); + bindAttributes( rootEntityBinding, rootEntitySource ); + if ( inheritanceTypes.peek() != InheritanceType.NO_INHERITANCE ) { + bindSubEntities( rootEntityBinding, rootEntitySource ); + } + } finally { + inheritanceTypes.pop(); + entityModes.pop(); } - EntityDiscriminator discriminator = new EntityDiscriminator( - relationalValue, - discriminatorSource.isInserted(), - discriminatorSource.isForced() - ); - - discriminator.getExplicitHibernateTypeDescriptor().setExplicitTypeName( - discriminatorSource.getExplicitHibernateTypeName() != null - ? discriminatorSource.getExplicitHibernateTypeName() - : "string" - ); - - entityBinding.getHierarchyDetails().setEntityDiscriminator( discriminator ); - entityBinding.setDiscriminatorMatchValue( entitySource.getDiscriminatorMatchValue() ); + return rootEntityBinding; + } - Type resolvedType = typeHelper.determineHibernateTypeFromDescriptor( discriminator.getExplicitHibernateTypeDescriptor() ); - if ( resolvedType != null ) { - typeHelper.pushHibernateTypeInformationDown( resolvedType, relationalValue ); + public void bindEntities( final Iterable< EntityHierarchy > entityHierarchies ) { + entitySourcesByName.clear(); + attributeSourcesByName.clear(); + inheritanceTypes.clear(); + entityModes.clear(); + bindingContexts.clear(); + // Index sources by name so we can find and resolve entities on the fly as references to them + // are encountered (e.g., within associations) + for ( final EntityHierarchy entityHierarchy : entityHierarchies ) { + entityHierarchiesByRootEntitySource.put( entityHierarchy.getRootEntitySource(), entityHierarchy ); + mapSourcesByName( entityHierarchy.getRootEntitySource() ); + } + // Bind each entity hierarchy + for ( final EntityHierarchy entityHierarchy : entityHierarchies ) { + bindEntities( entityHierarchy ); } } - private void bindDiscriminatorValue(SubclassEntitySource entitySource, EntityBinding entityBinding) { - final String discriminatorValue = entitySource.getDiscriminatorMatchValue(); - if ( discriminatorValue == null ) { - return; + private EntityBinding bindEntity( final EntitySource entitySource, + final EntityBinding superEntityBinding ) { + System.out.println( "bindEntity( entitySource = " + entitySource.getEntityName() + ", superEntityBinding = " + + ( superEntityBinding == null ? "null" : superEntityBinding.getEntity().getName() ) + " )" ); + // Return existing binding if available + EntityBinding entityBinding = metadata.getEntityBinding( entitySource.getEntityName() ); + if ( entityBinding != null ) { + return entityBinding; } - entityBinding.setDiscriminatorMatchValue( discriminatorValue ); + // Create new entity binding + entityBinding = createEntityBinding( entitySource, superEntityBinding ); + bindAttributes( entityBinding, entitySource ); + bindSubEntities( entityBinding, entitySource ); + return entityBinding; } - private void bindAttributes( - AttributeSourceContainer attributeSourceContainer, - AttributeBindingContainer attributeBindingContainer, - Deque tableStack) { - // todo : we really need the notion of a Stack here for the table from which the columns come for binding these attributes. - // todo : adding the concept (interface) of a source of attribute metadata would allow reuse of this method for entity, component, unique-key, etc - // for now, simply assume all columns come from the base table.... - - for ( AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) { - if ( attributeSource.isSingular() ) { - bindSingularAttribute( (SingularAttributeSource) attributeSource, attributeBindingContainer, tableStack ); + private void bindHibernateTypeDescriptor( final HibernateTypeDescriptor hibernateTypeDescriptor, + final ExplicitHibernateTypeSource typeSource, + final Attribute attribute, + final AbstractValue value ) { + String typeName = typeSource.getName(); + System.out.println( "bindHibernateTypeDescriptor( typeSource = " + typeSource.getName() + ", attribute = " + + attribute.getName() + " )" ); + // Check if user specified a type + if ( typeName == null ) { + // Obtain Java type name from attribute + final Class< ? > attributeJavaType = + ReflectHelper.reflectedPropertyClass( attribute.getAttributeContainer().getClassReference(), attribute.getName() ); + typeName = attributeJavaType.getName(); + hibernateTypeDescriptor.setJavaTypeName( typeName ); + } else { + // Check if user-specified name is of a User-Defined Type (UDT) + final TypeDefinition typeDef = metadata.getTypeDefinition( typeName ); + if ( typeDef == null ) { + hibernateTypeDescriptor.setExplicitTypeName( typeName ); + } else { + hibernateTypeDescriptor.setExplicitTypeName( typeDef.getTypeImplementorClass().getName() ); + hibernateTypeDescriptor.setTypeParameters( typeDef.getParameters() ); } - else { - bindPersistentCollection( (PluralAttributeSource) attributeSource, attributeBindingContainer, tableStack ); + final Map< String, String > typeParameters = typeSource.getParameters(); + if ( typeParameters != null ) { + hibernateTypeDescriptor.getTypeParameters().putAll( typeParameters ); } } + resolveHibernateResolvedType( hibernateTypeDescriptor, typeName, value ); } - private void bindSingularAttribute( - SingularAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer, - Deque tableStack) { - if ( attributeSource.getNature() == SingularAttributeNature.BASIC ) { - bindBasicAttribute( attributeSource, attributeBindingContainer ); - } - else if ( attributeSource.getNature() == SingularAttributeNature.COMPONENT ) { - bindComponentAttribute( (ComponentAttributeSource) attributeSource, attributeBindingContainer, tableStack ); - } - else if ( attributeSource.getNature() == SingularAttributeNature.ANY ) { - throw new NotYetImplementedException( "Handling of ANY mappings not yet implemented" ); - } - else { - bindToOneAttribute( (ToOneAttributeSource) attributeSource, attributeBindingContainer ); + private void bindIdentifier( final EntityBinding rootEntityBinding, + final IdentifierSource identifierSource ) { + final Nature nature = identifierSource.getNature(); + System.out.println( "bindIdentifier( " + rootEntityBinding.getEntity().getName() + " ): nature = " + nature ); + if ( nature == Nature.SIMPLE ) { + bindSimpleIdentifier( rootEntityBinding, ( SimpleIdentifierSource ) identifierSource ); + } else { + throw new NotYetImplementedException( nature.toString() ); + // } else if ( nature == Nature.AGGREGATED_COMPOSITE ) { + // // composite id with an actual component class + // } else if ( nature == Nature.COMPOSITE ) { + // // what we used to term an "embedded composite identifier", which is not to be confused with the JPA + // // term embedded. Specifically a composite id where there is no component class, though there may + // // be a @IdClass :/ } } - private SingularAttributeBinding bindToOneAttribute( - ToOneAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer) { - final SingularAttribute existingAttribute = attributeBindingContainer.getAttributeContainer() - .locateSingularAttribute( attributeSource.getName() ); - final SingularAttribute attribute; - if ( existingAttribute != null ) { - attribute = existingAttribute; - } - else if ( attributeSource.isVirtualAttribute() ) { - attribute = attributeBindingContainer.getAttributeContainer().createVirtualSingularAttribute( - attributeSource.getName() - ); - } - else { - attribute = attributeBindingContainer.getAttributeContainer() - .createSingularAttribute( attributeSource.getName() ); - } - - final List relationalValueBindings = createSimpleRelationalValues( - attributeSource, - attributeBindingContainer, - attribute, - attributeBindingContainer - .seekEntityBinding() - .getPrimaryTable() - ); - final String propertyAccessorName = Helper.getPropertyAccessorName( - attributeSource.getPropertyAccessorName(), - false, - currentBindingContext.getMappingDefaults().getPropertyAccessorName() - ); - final MetaAttributeContext metaAttributeContext = buildMetaAttributeContext( - attributeSource.metaAttributes(), - attributeBindingContainer.getMetaAttributeContext() - ); - - final SingularAssociationAttributeBinding attributeBinding; - if ( attributeSource.getNature() == SingularAttributeNature.ONE_TO_ONE ) { - throw new NotYetImplementedException( "Handling of one-to-one mappings not yet implemented" ); - } - else if ( attributeSource.getNature() == SingularAttributeNature.MANY_TO_ONE ) { - attributeBinding = attributeBindingContainer.makeManyToOneAttributeBinding( - attribute, - propertyAccessorName, - attributeSource.isIncludedInOptimisticLocking(), - attributeSource.isLazy(), - metaAttributeContext, - attributeSource.getReferencedEntityName(), - attributeSource.getReferencedEntityAttributeName(), - relationalValueBindings - ); - typeHelper.bindSingularAttributeTypeInformation( attributeSource, attributeBinding ); - resolveToOneInformation( - attributeSource, - (ManyToOneAttributeBinding) attributeBinding - ); - final String referencedEntityName = attributeBinding.getReferencedEntityName(); - EntityBinding referencedEntityBinding = getEntityBinding( referencedEntityName ); - if ( referencedEntityBinding == null ) { - EntitySource source = sourcesByName.get( referencedEntityName ); - createEntityBinding( source, referencedEntityBinding ); - } - AttributeBinding referencedAttrBinding = attributeSource.getReferencedEntityAttributeName() != null - ? referencedEntityBinding.locateAttributeBinding( attributeSource.getReferencedEntityAttributeName() ) - : referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(); - attributeBinding.resolveReference( referencedAttrBinding ); - referencedAttrBinding.addEntityReferencingAttributeBinding( attributeBinding ); - } - else { - throw new NotYetImplementedException(); - } - - return attributeBinding; + LocalBindingContext bindingContext() { + return bindingContexts.peek(); } - private ForeignKey resolveForeignKey( - ToOneAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer, - Attribute attribute) { - final String explicitForeignKeyName = attributeSource.getForeignKeyName(); - - // foreign key columns should all come from the same table... - final TableSpecification sourceTable = attributeBindingContainer.seekEntityBinding().locateTable( - attributeSource.relationalValueSources().get( 0 ).getContainingTableName() - ); - - ForeignKey foreignKey = sourceTable.locateForeignKey( explicitForeignKeyName ); - if ( foreignKey != null ) { - // todo : maybe validate columns? - return foreignKey; - } - - final List sourceColumns = new ArrayList(); - for ( RelationalValueSource relationalValueSource : attributeSource.relationalValueSources() ) { - sourceColumns.add( - makeRelationalValue( - sourceTable, - relationalValueSource, - attributeSource, - attribute - ) - ); - } - - // todo : pretty sure this is one of the places where the "chasing" approach implemented by john breaks down - // even assuming the best case that the target entity and its attributes are fully resolved, - // what about the self-referential (Employee<->Manager) case? - final EntityBinding referencedEntityBinding = metadata.getEntityBinding( attributeSource.getReferencedEntityName() ); - if ( referencedEntityBinding == null ) { - throw new MappingException( - "Unable to locate reference entity binding for association : " + attributeSource, - currentBindingContext.getOrigin() - ); - } + private ManyToOneAttributeBinding bindManyToOneAttribute( final AttributeBindingContainer attributeBindingContainer, + final ToOneAttributeSource attributeSource, + SingularAttribute attribute ) { + System.out.println( "bindManyToOneAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " )" ); + if ( attribute == null ) { + attribute = createSingularAttribute( attributeBindingContainer, attributeSource ); + } + final List< RelationalValueBinding > relationalValueBindings = + bindValues( attributeBindingContainer, + attributeSource, + attribute, + attributeBindingContainer.seekEntityBinding().getPrimaryTable() ); + final ManyToOneAttributeBinding attributeBinding = + attributeBindingContainer.makeManyToOneAttributeBinding( attribute, + propertyAccessorName( attributeSource ), + attributeSource.isIncludedInOptimisticLocking(), + attributeSource.isLazy(), + createMetaAttributeContext( attributeBindingContainer, + attributeSource ), + null, // this isn't passed to the binding constructor + null, // this isn't passed to the binding constructor + relationalValueBindings ); + bindHibernateTypeDescriptor( attributeBinding.getHibernateTypeDescriptor(), + attributeSource.getTypeInformation(), + attributeBinding.getAttribute(), + ( AbstractValue ) relationalValueBindings.get( 0 ).getValue() ); + final HibernateTypeDescriptor hibernateTypeDescriptor = attributeBinding.getHibernateTypeDescriptor(); + attribute.resolveType( bindingContexts.peek().makeJavaType( hibernateTypeDescriptor.getJavaTypeName() ) ); - // todo : try to look up the reverse FK based on the tables/columns... + attributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() ); + attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); + attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); - final TableSpecification targetTable; - final List targetColumns = new ArrayList(); - if ( StringHelper.isEmpty( attributeSource.getReferencedEntityAttributeName() ) ) { - List valueBindings = referencedEntityBinding.getHierarchyDetails() - .getEntityIdentifier() - .getValueBinding() - .getRelationalValueBindings(); - targetTable = valueBindings.get( 0 ).getValue().getTable(); - for ( RelationalValueBinding binding : valueBindings ) { - targetColumns.add( binding.getValue() ); - } - } - else { - // todo : this is very different for JPA which uses @JoinColumn and hbm which uses property-ref - // we need a scheme that works for both. - // the processing here uses hbm/property-ref approach - // - // the referenced property could conceivably be either a component or a basic - final SingularAttributeBinding referencedAttributeBinding = (SingularAttributeBinding) referencedEntityBinding.locateAttributeBinding( - attributeSource.getReferencedEntityAttributeName() - ); - if ( CompositeAttributeBinding.class.isInstance( referencedAttributeBinding ) ) { - collectValues( (CompositeAttributeBinding) referencedAttributeBinding, targetColumns ); - } - else { - for ( RelationalValueBinding valueBinding :( (BasicAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings() ) { - targetColumns.add( valueBinding.getValue() ); - } - } - targetTable = targetColumns.get( 0 ).getTable(); + String referencedEntityName = attributeSource.getReferencedEntityName(); + if ( referencedEntityName == null ) { + referencedEntityName = attribute.getSingularAttributeType().getClassName(); } + attributeBinding.setReferencedEntityName( referencedEntityName ); + final EntityBinding referencedEntityBinding = entityBinding( referencedEntityName ); + System.out.println( "bindManyToOneAttribute: referencedEntityBinding = " + referencedEntityBinding.getEntity().getName() ); + final String referencedAttributeName = attributeSource.getReferencedEntityAttributeName(); + System.out.println( "bindManyToOneAttribute: referencedAttributeName = " + referencedAttributeName ); + attributeBinding.setReferencedAttributeName( referencedAttributeName ); + final AttributeBinding referencedAttributeBinding = referencedAttributeName == null + ? referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() + : referencedEntityBinding.locateAttributeBinding( referencedAttributeName ); + System.out.println( "bindManyToOneAttribute: referencedAttributeBinding = " + referencedAttributeBinding ); + attributeBinding.resolveReference( referencedAttributeBinding ); + referencedAttributeBinding.addEntityReferencingAttributeBinding( attributeBinding ); + return attributeBinding; + } - if ( sourceColumns.size() != targetColumns.size() ) { - throw new MappingException( - "Encountered mismatch in number of columns in foreign key", - currentBindingContext.getOrigin() - ); - } - foreignKey = sourceTable.createForeignKey( targetTable, explicitForeignKeyName ); - for ( int i = 0; i < sourceColumns.size(); i++ ) { - // todo : handle special case of formulas in key mappings... - foreignKey.addColumnMapping( (Column) sourceColumns.get(i), (Column) targetColumns.get(i) ); + private AbstractPluralAttributeBinding bindPluralAttribute( final AttributeBindingContainer attributeBindingContainer, + final PluralAttributeSource attributeSource ) { + final PluralAttributeNature nature = attributeSource.getPluralAttributeNature(); + System.out.println( "bindPluralAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " ): nature = " + nature ); + final PluralAttribute attribute = + attributeBindingContainer.getAttributeContainer().locatePluralAttribute( attributeSource.getName() ); + AbstractPluralAttributeBinding attributeBinding; + if ( nature == PluralAttributeNature.BAG ) { + attributeBinding = bindBagAttribute( attributeBindingContainer, attributeSource, attribute ); + } else if ( nature == PluralAttributeNature.SET ) { + attributeBinding = bindSetAttribute( attributeBindingContainer, attributeSource, attribute ); + } else { + throw new NotYetImplementedException( nature.toString() ); } + attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); + attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); + attributeBinding.setCaching( attributeSource.getCaching() ); + attributeBinding.getHibernateTypeDescriptor().setJavaTypeName( nature.reportedJavaType().getName() ); + attributeBinding.getHibernateTypeDescriptor().setExplicitTypeName( attributeSource.getTypeInformation().getName() ); + attributeBinding.getHibernateTypeDescriptor().getTypeParameters().putAll( attributeSource.getTypeInformation(). + getParameters() ); + if ( StringHelper.isNotEmpty( attributeSource.getCustomPersisterClassName() ) ) { + attributeBinding.setExplicitPersisterClass( bindingContexts.peek(). + < CollectionPersister >locateClassByName( attributeSource. + getCustomPersisterClassName() ) ); + } + attributeBinding.setCustomLoaderName( attributeSource.getCustomLoaderName() ); + attributeBinding.setCustomSqlInsert( attributeSource.getCustomSqlInsert() ); + attributeBinding.setCustomSqlUpdate( attributeSource.getCustomSqlUpdate() ); + attributeBinding.setCustomSqlDelete( attributeSource.getCustomSqlDelete() ); + attributeBinding.setCustomSqlDeleteAll( attributeSource.getCustomSqlDeleteAll() ); + attributeBinding.setWhere( attributeSource.getWhere() ); + bindCollectionTable( attributeBinding, attributeSource ); + bindSortingAndOrdering( attributeBinding, attributeSource ); + bindCollectionKey( attributeBinding, attributeSource ); + bindCollectionElement( attributeBinding, attributeSource ); + bindCollectionIndex( attributeBinding, attributeSource ); + bindCollectionTablePrimaryKey( attributeBinding, attributeSource ); + typeHelper.bindPluralAttributeTypeInformation( attributeSource, attributeBinding ); + metadata.addCollection( attributeBinding ); + return attributeBinding; + } + + private void bindPrimaryTable( final EntityBinding entityBinding, + final EntitySource entitySource ) { + entityBinding.setPrimaryTable( createTable( entitySource.getPrimaryTable(), new DefaultNamingStrategy() { - return foreignKey; + @Override + public String defaultName() { + return bindingContexts.peek().getNamingStrategy().classToTableName( entityBinding.getEntity().getClassName() ); + } + } ) ); } - private void collectValues(CompositeAttributeBinding compositeAttributeBinding, List targetColumns) { - for ( AttributeBinding attributeBinding : compositeAttributeBinding.attributeBindings() ) { - if ( BasicAttributeBinding.class.isInstance( attributeBinding ) ) { - for ( RelationalValueBinding valueBinding :( (BasicAttributeBinding) attributeBinding ).getRelationalValueBindings() ) { - targetColumns.add( valueBinding.getValue() ); + private void bindSecondaryTables( final EntityBinding entityBinding, + final EntitySource entitySource ) { + System.out.println( "bindSecondaryTables( entityBinding = " + entitySource.getEntityName() + " )" ); + final TableSpecification primaryTable = entityBinding.getPrimaryTable(); + for ( final SecondaryTableSource secondaryTableSource : entitySource.getSecondaryTables() ) { + final TableSpecification table = createTable( secondaryTableSource.getTableSource(), null ); + // todo: really need a concept like SecondaryTableSource in the binding model as well + // so that EntityBinding can know the proper foreign key to use to build SQL statements. + ForeignKey foreignKey = null; + if ( secondaryTableSource.getForeignKeyName() == null ) { + // todo: for now lets assume we have to create it, but eventually we should look through the + // candidate foreign keys referencing primary table also... + foreignKey = table.createForeignKey( primaryTable, null ); + } else { + foreignKey = table.locateForeignKey( secondaryTableSource.getForeignKeyName() ); + if ( foreignKey == null ) { + foreignKey = table.createForeignKey( primaryTable, secondaryTableSource.getForeignKeyName() ); } } - else if ( ManyToOneAttributeBinding.class.isInstance( attributeBinding ) ) { - for ( RelationalValueBinding valueBinding :( (BasicAttributeBinding) attributeBinding ).getRelationalValueBindings() ) { - targetColumns.add( valueBinding.getValue() ); + for ( final PrimaryKeyJoinColumnSource joinColumnSource : secondaryTableSource.getJoinColumns() ) { + // todo : currently we only support columns here, not formulas + // todo : apply naming strategy to infer missing column name + Column column = table.locateColumn( joinColumnSource.getColumnName() ); + if ( column == null ) { + column = table.createColumn( joinColumnSource.getColumnName() ); + if ( joinColumnSource.getColumnDefinition() != null ) { + column.setSqlType( joinColumnSource.getColumnDefinition() ); + } + } + if ( joinColumnSource.getReferencedColumnName() == null ) { + foreignKey.addColumn( column ); + } else { + foreignKey.addColumnMapping( column, primaryTable.locateColumn( joinColumnSource.getReferencedColumnName() ) ); } } - else if ( CompositeAttributeBinding.class.isInstance( attributeBinding ) ) { - collectValues( (CompositeAttributeBinding) attributeBinding, targetColumns ); - } + entityBinding.addSecondaryTable( new SecondaryTable( table, foreignKey ) ); } } - private BasicAttributeBinding bindBasicAttribute( - SingularAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer) { - final SingularAttribute existingAttribute = attributeBindingContainer.getAttributeContainer() - .locateSingularAttribute( attributeSource.getName() ); - final SingularAttribute attribute; - if ( existingAttribute != null ) { - attribute = existingAttribute; - } - else if ( attributeSource.isVirtualAttribute() ) { - attribute = attributeBindingContainer.getAttributeContainer().createVirtualSingularAttribute( - attributeSource.getName() - ); - } - else { - attribute = attributeBindingContainer.getAttributeContainer() - .createSingularAttribute( attributeSource.getName() ); - } - - final List relationalValueBindings = createSimpleRelationalValues( - attributeSource, - attributeBindingContainer, - attribute, - attributeBindingContainer - .seekEntityBinding() - .getPrimaryTable() - ); - final String propertyAccessorName = Helper.getPropertyAccessorName( - attributeSource.getPropertyAccessorName(), - false, - currentBindingContext.getMappingDefaults().getPropertyAccessorName() - ); - final MetaAttributeContext metaAttributeContext = buildMetaAttributeContext( - attributeSource.metaAttributes(), - attributeBindingContainer.getMetaAttributeContext() - ); - - final BasicAttributeBinding attributeBinding = attributeBindingContainer.makeBasicAttributeBinding( - attribute, - relationalValueBindings, - propertyAccessorName, - attributeSource.isIncludedInOptimisticLocking(), - attributeSource.isLazy(), - metaAttributeContext, - attributeSource.getGeneration() - ); - typeHelper.bindSingularAttributeTypeInformation( attributeSource, attributeBinding ); - return attributeBinding; - } - - private void bindComponentAttribute( - ComponentAttributeSource attributeSource, - AttributeBindingContainer container, - Deque tableStack) { - final String attributeName = attributeSource.getName(); - SingularAttribute attribute = container.getAttributeContainer().locateCompositeAttribute( attributeName ); - final Composite composite; + private AbstractPluralAttributeBinding bindSetAttribute( final AttributeBindingContainer attributeBindingContainer, + final PluralAttributeSource attributeSource, + PluralAttribute attribute ) { if ( attribute == null ) { - composite = new Composite( - attributeSource.getPath(), - attributeSource.getClassName(), - attributeSource.getClassReference(), - null // composition inheritance not YET supported - ); - attribute = container.getAttributeContainer().createCompositeAttribute( attributeName, composite ); - } - else { - composite = (Composite) attribute.getSingularAttributeType(); - } - - final String propertyAccessorName = Helper.getPropertyAccessorName( - attributeSource.getPropertyAccessorName(), - false, - currentBindingContext.getMappingDefaults().getPropertyAccessorName() - ); - final MetaAttributeContext metaAttributeContext = buildMetaAttributeContext( - attributeSource.metaAttributes(), - container.getMetaAttributeContext() - ); - - final SingularAttribute parentReferenceAttribute; - if ( StringHelper.isNotEmpty( attributeSource.getParentReferenceAttributeName() ) ) { - parentReferenceAttribute = composite.createSingularAttribute( attributeSource.getParentReferenceAttributeName() ); - } - else { - parentReferenceAttribute = null; - } - - CompositeAttributeBinding compositeAttributeBinding = container.makeComponentAttributeBinding( - attribute, - parentReferenceAttribute, - propertyAccessorName, - attributeSource.isIncludedInOptimisticLocking(), - attributeSource.isLazy(), - metaAttributeContext - ); - - bindAttributes( attributeSource, compositeAttributeBinding, tableStack ); - } - - private void bindPersistentCollection( - PluralAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer, - Deque tableStack) { - final PluralAttribute existingAttribute = attributeBindingContainer.getAttributeContainer() - .locatePluralAttribute( attributeSource.getName() ); - final AbstractPluralAttributeBinding pluralAttributeBinding; - - final String propertyAccessorName = Helper.getPropertyAccessorName( - attributeSource.getPropertyAccessorName(), - false, - currentBindingContext.getMappingDefaults().getPropertyAccessorName() - ); - final MetaAttributeContext metaAttributeContext = buildMetaAttributeContext( - attributeSource.metaAttributes(), - attributeBindingContainer.getMetaAttributeContext() - ); - - // TODO: referenced attribute binding may not be defined yet; if it doesn't, need to chase it - // before resolving types. - SingularAttributeBinding referencedAttributeBinding = locatePluralAttributeKeyReferencedBinding( - attributeSource, attributeBindingContainer - ); - if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) { - final PluralAttribute attribute = existingAttribute != null - ? existingAttribute - : attributeBindingContainer.getAttributeContainer().createBag( attributeSource.getName() ); - pluralAttributeBinding = attributeBindingContainer.makeBagAttributeBinding( - attribute, - convert( attributeSource.getElementSource().getNature() ), - referencedAttributeBinding, - propertyAccessorName, - attributeSource.isIncludedInOptimisticLocking(), - false, - metaAttributeContext - ); - } - else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SET ) { - final PluralAttribute attribute = existingAttribute != null - ? existingAttribute - : attributeBindingContainer.getAttributeContainer().createSet( attributeSource.getName() ); - final Comparator comparator = null; - pluralAttributeBinding = attributeBindingContainer.makeSetAttributeBinding( - attribute, - convert( attributeSource.getElementSource().getNature() ), - referencedAttributeBinding, - propertyAccessorName, - attributeSource.isIncludedInOptimisticLocking(), - false, - metaAttributeContext, - comparator - ); - } - else { - // todo : implement other collection types - throw new NotYetImplementedException( "Collections other than bag and set not yet implemented :(" ); - } - - doBasicPluralAttributeBinding( attributeSource, pluralAttributeBinding ); - - bindCollectionTable( attributeSource, pluralAttributeBinding ); - bindSortingAndOrdering( attributeSource, pluralAttributeBinding ); - - bindCollectionKey( attributeSource, pluralAttributeBinding, tableStack ); - bindCollectionElement( attributeSource, pluralAttributeBinding ); - bindCollectionIndex( attributeSource, pluralAttributeBinding ); - bindCollectionTablePrimaryKey( attributeSource, pluralAttributeBinding ); - - typeHelper.bindPluralAttributeTypeInformation( attributeSource, pluralAttributeBinding ); - - metadata.addCollection( pluralAttributeBinding ); + attribute = attributeBindingContainer.getAttributeContainer().createSet( attributeSource.getName() ); + } + return attributeBindingContainer.makeSetAttributeBinding( attribute, + pluralAttributeElementNature( attributeSource ), + pluralAttributeKeyBinding( attributeBindingContainer, + attributeSource ), + propertyAccessorName( attributeSource ), + attributeSource.isIncludedInOptimisticLocking(), + false, + createMetaAttributeContext( attributeBindingContainer, + attributeSource ), + null ); } - private SingularAttributeBinding locatePluralAttributeKeyReferencedBinding( - PluralAttributeSource attributeSource, - AttributeBindingContainer attributeBindingContainer) { - final EntityBinding entityBinding = attributeBindingContainer.seekEntityBinding(); - final String referencedAttributeName = attributeSource.getKeySource().getReferencedEntityAttributeName(); - AttributeBinding referencedAttributeBinding = - attributeSource.getKeySource().getReferencedEntityAttributeName() == null ? - entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() : - entityBinding.locateAttributeBinding( referencedAttributeName ); - if ( referencedAttributeBinding == null ) { - throw new MappingException( - String.format( - "Plural atttribute key references an attribute binding that does not exist: %s", - referencedAttributeBinding - ), - currentBindingContext.getOrigin() - ); + private void bindSimpleIdentifier( final EntityBinding rootEntityBinding, + final SimpleIdentifierSource identifierSource ) { + final BasicAttributeBinding idAttributeBinding = + ( BasicAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() ); + System.out.println( "bindSimpleIdentifier( " + rootEntityBinding.getEntity().getName() + ", " + + identifierSource.getIdentifierAttributeSource().getName() + " )" ); + rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding ); + // Configure ID generator + IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor(); + if ( generator == null ) { + final Map< String, String > params = new HashMap< String, String >(); + params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() ); + generator = new IdGenerator( "default_assign_identity_generator", "assigned", params ); } - if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { - throw new MappingException( - String.format( - "Plural atttribute key references a plural attribute; it must be plural: %s", - referencedAttributeName - ), - currentBindingContext.getOrigin() - ); + rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setIdGenerator( generator ); + // Configure primary key in relational model + for ( final RelationalValueBinding valueBinding : idAttributeBinding.getRelationalValueBindings() ) { + rootEntityBinding.getPrimaryTable().getPrimaryKey().addColumn( ( Column ) valueBinding.getValue() ); } - return ( SingularAttributeBinding ) referencedAttributeBinding; } - private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) { - binding.setFetchTiming( source.getFetchTiming() ); - binding.setFetchStyle( source.getFetchStyle() ); - - binding.setCaching( source.getCaching() ); - - binding.getHibernateTypeDescriptor().setJavaTypeName( - source.getPluralAttributeNature().reportedJavaType().getName() - ); - binding.getHibernateTypeDescriptor().setExplicitTypeName( source.getTypeInformation().getName() ); - binding.getHibernateTypeDescriptor().getTypeParameters().putAll( source.getTypeInformation().getParameters() ); - - if ( StringHelper.isNotEmpty( source.getCustomPersisterClassName() ) ) { - binding.setExplicitPersisterClass( - currentBindingContext.locateClassByName( source.getCustomPersisterClassName() ) - ); - } - - binding.setCustomLoaderName( source.getCustomLoaderName() ); - binding.setCustomSqlInsert( source.getCustomSqlInsert() ); - binding.setCustomSqlUpdate( source.getCustomSqlUpdate() ); - binding.setCustomSqlDelete( source.getCustomSqlDelete() ); - binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() ); - - binding.setWhere( source.getWhere() ); - -// doBasicAttributeBinding( source, binding ); + private SingularAttributeBinding bindSingularAttribute( final AttributeBindingContainer attributeBindingContainer, + final SingularAttributeSource attributeSource ) { + final SingularAttributeNature nature = attributeSource.getNature(); + System.out.println( "bindSingularAttribute( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attributeSource.getName() + " ): nature = " + nature ); + final SingularAttribute attribute = + attributeBindingContainer.getAttributeContainer().locateSingularAttribute( attributeSource.getName() ); + if ( nature == SingularAttributeNature.BASIC ) { + return bindBasicAttribute( attributeBindingContainer, attributeSource, attribute ); + } + if ( nature == SingularAttributeNature.MANY_TO_ONE ) { + return bindManyToOneAttribute( attributeBindingContainer, ( ToOneAttributeSource ) attributeSource, attribute ); + } + if ( nature == SingularAttributeNature.COMPONENT ) { + return bindComponentAttribute( attributeBindingContainer, + ( ComponentAttributeSource ) attributeSource, + attribute ); + } + throw new NotYetImplementedException( nature.toString() ); } -// private CollectionLaziness interpretLaziness(String laziness) { -// if ( laziness == null ) { -// laziness = Boolean.toString( metadata.getMappingDefaults().areAssociationsLazy() ); -// } -// -// if ( "extra".equals( laziness ) ) { -// return CollectionLaziness.EXTRA; -// } -// else if ( "false".equals( laziness ) ) { -// return CollectionLaziness.NOT; -// } -// else if ( "true".equals( laziness ) ) { -// return CollectionLaziness.LAZY; -// } -// -// throw new MappingException( -// String.format( "Unexpected collection laziness value %s", laziness ), -// currentBindingContext.getOrigin() -// ); -// } - - private void bindCollectionTable( - final PluralAttributeSource attributeSource, - final AbstractPluralAttributeBinding pluralAttributeBinding) { - if ( attributeSource.getElementSource().getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.ONE_TO_MANY ) { + private void bindSortingAndOrdering( final AbstractPluralAttributeBinding attributeBinding, + final PluralAttributeSource attributeSource ) { + if ( Sortable.class.isInstance( attributeSource ) ) { + final Sortable sortable = ( Sortable ) attributeSource; + if ( sortable.isSorted() ) { + // todo : handle setting comparator + } + // Return because sorting and ordering are mutually exclusive return; } - - TableSpecificationSource tableSpecificationSource = attributeSource.getCollectionTableSpecificationSource(); - if ( TableSource.class.isInstance( tableSpecificationSource ) ) { - Table collectionTable = createTable( - (TableSource) tableSpecificationSource, - new InferredNamingStrategy() { - @Override - public String inferredTableName() { - final EntityBinding owner = pluralAttributeBinding.getContainer().seekEntityBinding(); - final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() ) - ? Table.class.cast( owner.getPrimaryTable() ).getTableName().getName() - : null; - return currentBindingContext.getNamingStrategy().collectionTableName( - owner.getEntity().getName(), - ownerTableLogicalName, - null, // todo : here - null, // todo : and here - pluralAttributeBinding.getContainer().getPathBase() + '.' + attributeSource.getName() - ); - } - } - ); - pluralAttributeBinding.setCollectionTable( collectionTable ); - } - else { - pluralAttributeBinding.setCollectionTable( createInLineView( (InLineViewSource) tableSpecificationSource ) ); - } - - if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableComment() ) ) { - pluralAttributeBinding.getCollectionTable().addComment( attributeSource.getCollectionTableComment() ); + if ( Orderable.class.isInstance( attributeSource ) ) { + final Orderable orderable = ( Orderable ) attributeSource; + if ( orderable.isOrdered() ) { + // todo : handle setting ordering + } } - - if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) { - pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() ); - } } - - private void bindCollectionKey( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding, - Deque tableStack) { - - final PluralAttributeKeySource keySource = attributeSource.getKeySource(); - - String foreignKeyName = ( - StringHelper.isNotEmpty( keySource.getExplicitForeignKeyName() ) ? - quoteIdentifier( keySource.getExplicitForeignKeyName() ) : - null // TODO: is null FK name allowd (is there a default?) - ); - pluralAttributeBinding.getPluralAttributeKeyBinding().prepareForeignKey( - foreignKeyName, - tableStack.peekLast() - ); - final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey(); - - foreignKey.setDeleteRule( keySource.getOnDeleteAction() ); - if ( keySource.getReferencedEntityAttributeName() == null ) { - bindCollectionKeyTargetingPrimaryKey( attributeSource.getKeySource(), pluralAttributeBinding ); - } - else { - bindCollectionKeyTargetingPropertyRef( attributeSource.getKeySource(), pluralAttributeBinding ); + private void bindSubEntities( final EntityBinding entityBinding, + final EntitySource entitySource ) { + for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) { + bindEntity( subEntitySource, entityBinding ); } } - private void bindCollectionKeyTargetingPrimaryKey( - PluralAttributeKeySource keySource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - - for ( RelationalValueSource valueSource : keySource.getValueSources() ) { - if ( ColumnSource.class.isInstance( valueSource ) ) { - final Column column = makeColumn( - ColumnSource.class.cast( valueSource ), - COLL_KEY_COLUMN_BINDING_DEFAULTS, - pluralAttributeBinding.getCollectionTable(), - pluralAttributeBinding.getAttribute().getName(), - true - ); - pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().addColumn( column ); - } - else { - // TODO: deal with formulas??? + private void bindUniqueConstraints( final EntityBinding entityBinding, + final EntitySource entitySource ) { + for ( final ConstraintSource constraintSource : entitySource.getConstraints() ) { + if ( constraintSource instanceof UniqueConstraintSource ) { + final TableSpecification table = entityBinding.locateTable( constraintSource.getTableName() ); + final String constraintName = constraintSource.name(); + if ( constraintName == null ) { + throw new NotYetImplementedException( "create default constraint name" ); + } + final UniqueKey uniqueKey = table.getOrCreateUniqueKey( constraintName ); + for ( final String columnName : constraintSource.columnNames() ) { + uniqueKey.addColumn( table.locateOrCreateColumn( quotedIdentifier( columnName ) ) ); + } } } } - private void bindCollectionKeyTargetingPropertyRef( - PluralAttributeKeySource keySource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - final EntityBinding ownerEntityBinding = pluralAttributeBinding.getContainer().seekEntityBinding(); - final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding( - keySource.getReferencedEntityAttributeName() - ); - final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey(); - if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { - throw new MappingException( - String.format( - "Collection (%s) property-ref is a plural attribute (%s); must be singular.", - pluralAttributeBinding.getAttribute().getRole(), - referencedAttributeBinding - ), - currentBindingContext.getOrigin() - ); - } - Iterator targetValueBindings = - ( (SingularAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings().iterator(); - for ( RelationalValueSource valueSource : keySource.getValueSources() ) { - if ( ! targetValueBindings.hasNext() ) { - throw new MappingException( - String.format( - "More collection key source columns than target columns for collection: %s", - pluralAttributeBinding.getAttribute().getRole() - ), - currentBindingContext.getOrigin() - ); - } - Value targetValue = targetValueBindings.next().getValue(); - if ( ColumnSource.class.isInstance( valueSource ) ) { - final ColumnSource columnSource = ColumnSource.class.cast( valueSource ); - final Column column = makeColumn( - columnSource, - COLL_KEY_COLUMN_BINDING_DEFAULTS, - pluralAttributeBinding.getCollectionTable(), - pluralAttributeBinding.getAttribute().getName(), - true - ); - if ( targetValue != null && ! Column.class.isInstance( targetValue ) ) { - throw new MappingException( - String.format( - "Type mismatch between collection key source and target; collection: %s; source column (%s) corresponds with target derived value (%s).", - pluralAttributeBinding.getAttribute().getRole(), - columnSource.getName(), - DerivedValue.class.cast( targetValue ).getExpression() - ), - currentBindingContext.getOrigin() - ); + private List< RelationalValueBinding > bindValues( final AttributeBindingContainer attributeBindingContainer, + final RelationalValueSourceContainer valueSourceContainer, + final Attribute attribute, + final TableSpecification defaultTable ) { + System.out.println( "bindValues( " + attributeBindingContainer.getAttributeContainer().getName() + ", " + + attribute.getName() + " )" ); + final List< RelationalValueBinding > valueBindings = new ArrayList< RelationalValueBinding >(); + if ( valueSourceContainer.relationalValueSources().isEmpty() ) { + final String columnName = + quotedIdentifier( bindingContexts.peek().getNamingStrategy().propertyToColumnName( attribute.getName() ) ); + final Column column = defaultTable.locateOrCreateColumn( columnName ); + System.out.println( "bindValues: \"" + column.getColumnName().getName() + "\" column on primary table " + + defaultTable.getLogicalName() ); + column.setNullable( valueSourceContainer.areValuesNullableByDefault() ); + valueBindings.add( new RelationalValueBinding( column ) ); + } else { + final String name = attribute.getName(); + for ( final RelationalValueSource valueSource : valueSourceContainer.relationalValueSources() ) { + final TableSpecification table = + valueSource.getContainingTableName() == null + ? defaultTable + : attributeBindingContainer.seekEntityBinding().locateTable( valueSource.getContainingTableName() ); + if ( valueSource instanceof ColumnSource ) { + final ColumnSource columnSource = ( ColumnSource ) valueSource; + final boolean isIncludedInInsert = toBoolean( columnSource.isIncludedInInsert(), + valueSourceContainer.areValuesIncludedInInsertByDefault() ); + final boolean isIncludedInUpdate = toBoolean( columnSource.isIncludedInUpdate(), + valueSourceContainer.areValuesIncludedInUpdateByDefault() ); + + valueBindings.add( new RelationalValueBinding( createColumn( table, + columnSource, + name, + valueSourceContainer.areValuesNullableByDefault(), + true ), + isIncludedInInsert, isIncludedInUpdate ) ); + } else { + final DerivedValue derivedValue = + table.locateOrCreateDerivedValue( ( ( DerivedValueSource ) valueSource ).getExpression() ); + valueBindings.add( new RelationalValueBinding( derivedValue ) ); } - foreignKey.addColumnMapping( column, Column.class.cast( targetValue ) ); - } - else { - // TODO: deal with formulas??? } } - if ( targetValueBindings != null && targetValueBindings.hasNext() ) { - throw new MappingException( - String.format( - "More collection key target columns than source columns for collection: %s", - pluralAttributeBinding.getAttribute().getRole() - ), - currentBindingContext.getOrigin() - ); - } + return valueBindings; } - private void bindCollectionTablePrimaryKey( - final PluralAttributeSource attributeSource, - final AbstractPluralAttributeBinding pluralAttributeBinding) { - if ( attributeSource.getElementSource().getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.ONE_TO_MANY || - attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) { + private void bindVersion( final EntityBinding rootEntityBinding, + final VersionAttributeSource versionAttributeSource ) { + if ( versionAttributeSource == null ) { return; } - if ( pluralAttributeBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.BASIC ) { - if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SET ) { - bindBasicElementSetTablePrimaryKey( ( SetBinding ) pluralAttributeBinding ); - } - else { - throw new NotYetImplementedException( "Only Sets with basic elements are supported so far." ); - } - } + System.out.println( "bindVersion( " + rootEntityBinding.getEntity().getName() + " ): " + versionAttributeSource.getName() ); + final EntityVersion version = rootEntityBinding.getHierarchyDetails().getEntityVersion(); + version.setVersioningAttributeBinding( ( BasicAttributeBinding ) bindAttribute( rootEntityBinding, + versionAttributeSource ) ); + version.setUnsavedValue( versionAttributeSource.getUnsavedValue() ); } - private void bindBasicElementSetTablePrimaryKey(SetBinding setBinding) { - - final PrimaryKey pk = setBinding.getCollectionTable().getPrimaryKey(); - final ForeignKey foreignKey = setBinding.getPluralAttributeKeyBinding().getForeignKey(); - - final BasicPluralAttributeElementBinding elementBinding = - ( BasicPluralAttributeElementBinding ) setBinding.getPluralAttributeElementBinding(); - if ( elementBinding.getPluralAttributeElementNature() != PluralAttributeElementNature.BASIC ) { - throw new IllegalArgumentException( - String.format( - "Expected a SetBinding with an element of nature PluralAttributeElementNature.BASIC; instead was %s", - elementBinding.getPluralAttributeElementNature() - ) - ); - } - - for ( Column foreignKeyColumn : foreignKey.getSourceColumns() ) { - pk.addColumn( foreignKeyColumn ); - } - - for ( RelationalValueBinding elementValueBinding : elementBinding.getRelationalValueBindings() ) { - if ( Column.class.isInstance( elementValueBinding.getValue() ) && !elementValueBinding.isNullable() ) { - pk.addColumn( ( Column ) elementValueBinding.getValue() ); - } + private Column createColumn( final TableSpecification table, + final ColumnSource columnSource, + final String defaultName, + final boolean isNullableByDefault, + final boolean isDefaultAttributeName ) { + if ( columnSource.getName() == null && defaultName == null ) { + throw new MappingException( "Cannot resolve name for column because no name was specified and default name is null.", + bindingContexts.peek().getOrigin() ); } - if ( pk.getColumnSpan() == foreignKey.getColumnSpan() ) { - //for backward compatibility, allow a set with no not-null - //element columns, using all columns in the row locater SQL - //TODO: create an implicit not null constraint on all cols? + String name; + if ( columnSource.getName() != null ) { + name = bindingContexts.peek().getNamingStrategy().columnName( columnSource.getName() ); + } else if ( isDefaultAttributeName ) { + name = bindingContexts.peek().getNamingStrategy().propertyToColumnName( defaultName ); + } else { + name = bindingContexts.peek().getNamingStrategy().columnName( defaultName ); } + final String resolvedColumnName = quotedIdentifier( name ); + final Column column = table.locateOrCreateColumn( resolvedColumnName ); + column.setNullable( toBoolean( columnSource.isNullable(), isNullableByDefault ) ); + column.setDefaultValue( columnSource.getDefaultValue() ); + column.setSqlType( columnSource.getSqlType() ); + column.setSize( columnSource.getSize() ); + column.setJdbcDataType( columnSource.getDatatype() ); + column.setReadFragment( columnSource.getReadFragment() ); + column.setWriteFragment( columnSource.getWriteFragment() ); + column.setUnique( columnSource.isUnique() ); + column.setCheckCondition( columnSource.getCheckCondition() ); + column.setComment( columnSource.getComment() ); + return column; } - private static final ColumnBindingDefaults COLL_KEY_COLUMN_BINDING_DEFAULTS = new ColumnBindingDefaults() { - @Override - public boolean areValuesIncludedInInsertByDefault() { - return true; - } - - @Override - public boolean areValuesIncludedInUpdateByDefault() { - return false; - } - - @Override - public boolean areValuesNullableByDefault() { - return false; - } - }; + private EntityBinding createEntityBinding( final EntitySource entitySource, + final EntityBinding superEntityBinding ) { + System.out.println( "createEntityBinding( entitySource = " + entitySource.getEntityName() + ", superEntityBinding = " + + ( superEntityBinding == null ? "null" : superEntityBinding.getEntity().getName() ) + " )" ); + final LocalBindingContext bindingContext = entitySource.getLocalBindingContext(); + bindingContexts.push( bindingContext ); + try { + // Create binding + final InheritanceType inheritanceType = inheritanceTypes.peek(); + final EntityMode entityMode = entityModes.peek(); + final EntityBinding entityBinding = entitySource instanceof RootEntitySource + ? new EntityBinding( inheritanceType, entityMode ) + : new EntityBinding( superEntityBinding ); + // Create domain entity + final String entityClassName = entityMode == EntityMode.POJO ? entitySource.getClassName() : null; + entityBinding.setEntity( new Entity( entitySource.getEntityName(), entityClassName, + bindingContext.makeClassReference( entityClassName ), + superEntityBinding == null ? null : superEntityBinding.getEntity() ) ); + // Create relational table + if ( superEntityBinding != null && inheritanceType == InheritanceType.SINGLE_TABLE ) { + entityBinding.setPrimaryTable( superEntityBinding.getPrimaryTable() ); + entityBinding.setPrimaryTableName( superEntityBinding.getPrimaryTableName() ); + // Configure discriminator if present + final String discriminatorValue = entitySource.getDiscriminatorMatchValue(); + if ( discriminatorValue != null ) { + entityBinding.setDiscriminatorMatchValue( discriminatorValue ); + } + } else { + bindPrimaryTable( entityBinding, entitySource ); + } + // todo: deal with joined and unioned subclass bindings + // todo: bind fetch profiles + // Configure rest of binding + final String customTuplizerClassName = entitySource.getCustomTuplizerClassName(); + if ( customTuplizerClassName != null ) { + entityBinding.setCustomEntityTuplizerClass( bindingContext. + < EntityTuplizer >locateClassByName( customTuplizerClassName ) ); + } + final String customPersisterClassName = entitySource.getCustomPersisterClassName(); + if ( customPersisterClassName != null ) { + entityBinding.setCustomEntityPersisterClass( bindingContext. + < EntityPersister >locateClassByName( customPersisterClassName ) ); + } + entityBinding.setMetaAttributeContext( createMetaAttributeContext( entitySource.metaAttributes(), + true, + metadata.getGlobalMetaAttributeContext() ) ); + entityBinding.setJpaEntityName( entitySource.getJpaEntityName() ); + entityBinding.setDynamicUpdate( entitySource.isDynamicUpdate() ); + entityBinding.setDynamicInsert( entitySource.isDynamicInsert() ); + entityBinding.setBatchSize( entitySource.getBatchSize() ); + entityBinding.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() ); + entityBinding.setAbstract( entitySource.isAbstract() ); + + entityBinding.setCustomLoaderName( entitySource.getCustomLoaderName() ); + entityBinding.setCustomInsert( entitySource.getCustomSqlInsert() ); + entityBinding.setCustomUpdate( entitySource.getCustomSqlUpdate() ); + entityBinding.setCustomDelete( entitySource.getCustomSqlDelete() ); + entityBinding.setJpaCallbackClasses( entitySource.getJpaCallbackClasses() ); + if ( entitySource.getSynchronizedTableNames() != null ) { + entityBinding.addSynchronizedTableNames( entitySource.getSynchronizedTableNames() ); + } + if ( entityMode == EntityMode.POJO ) { + final String proxy = entitySource.getProxy(); + if ( proxy == null ) { + if ( entitySource.isLazy() ) { + entityBinding.setProxyInterfaceType( entityBinding.getEntity().getClassReferenceUnresolved() ); + entityBinding.setLazy( true ); + } + } else { + entityBinding.setProxyInterfaceType( bindingContext.makeClassReference( bindingContext.qualifyClassName( proxy ) ) ); + entityBinding.setLazy( true ); + } + } else { + entityBinding.setProxyInterfaceType( null ); + entityBinding.setLazy( entitySource.isLazy() ); + } + bindSecondaryTables( entityBinding, entitySource ); + bindUniqueConstraints( entityBinding, entitySource ); + // Register binding with metadata + metadata.addEntity( entityBinding ); + return entityBinding; + } finally { - private void bindCollectionElement( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - final PluralAttributeElementSource elementSource = attributeSource.getElementSource(); - if ( elementSource.getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.BASIC ) { - final BasicPluralAttributeElementSource basicElementSource = - (BasicPluralAttributeElementSource) elementSource; - final BasicPluralAttributeElementBinding basicCollectionElement = - (BasicPluralAttributeElementBinding) pluralAttributeBinding.getPluralAttributeElementBinding(); - bindBasicPluralElementRelationalValues( - basicElementSource, - basicCollectionElement - ); - return; } - -// todo : handle cascades -// final Cascadeable cascadeable = (Cascadeable) binding.getPluralAttributeElementBinding(); -// cascadeable.setCascadeStyles( source.getCascadeStyles() ); - - // todo : implement - throw new NotYetImplementedException( - String.format( - "Support for collection elements of type %s not yet implemented", - elementSource.getNature() - ) - ); - } - - private void bindBasicPluralElementRelationalValues( - RelationalValueSourceContainer relationalValueSourceContainer, - BasicPluralAttributeElementBinding elementBinding) { - elementBinding.setRelationalValueBindings( - createSimpleRelationalValues( - relationalValueSourceContainer, - elementBinding.getPluralAttributeBinding().getContainer(), - elementBinding.getPluralAttributeBinding().getAttribute(), - elementBinding.getPluralAttributeBinding().getCollectionTable() - ) - ); } - private void bindCollectionIndex( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - if ( attributeSource.getPluralAttributeNature() != PluralAttributeNature.LIST - && attributeSource.getPluralAttributeNature() != PluralAttributeNature.MAP ) { - return; + private Identifier createIdentifier( String name, + final String defaultName ) { + System.out.println( "createIdentifier( name = " + name + ", defaultName = " + defaultName + " )" ); + if ( StringHelper.isEmpty( name ) ) { + name = defaultName; } - - // todo : implement - throw new NotYetImplementedException(); + name = quotedIdentifier( name ); + return Identifier.toIdentifier( name ); } - private void bindSortingAndOrdering( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - if ( Sortable.class.isInstance( attributeSource ) ) { - final Sortable sortable = Sortable.class.cast( attributeSource ); - if ( sortable.isSorted() ) { - // todo : handle setting comparator - - // and then return because sorting and ordering are mutually exclusive - return; - } + private void createIdentifierGenerator( final EntityBinding rootEntityBinding ) { + System.out.println( "createIdentifierGenerator( " + rootEntityBinding.getEntity().getName() + " )" ); + final Properties properties = new Properties(); + properties.putAll( metadata.getServiceRegistry().getService( ConfigurationService.class ).getSettings() ); + if ( !properties.contains( AvailableSettings.PREFER_POOLED_VALUES_LO ) ) { + properties.put( AvailableSettings.PREFER_POOLED_VALUES_LO, "false" ); } - - if ( Orderable.class.isInstance( attributeSource ) ) { - final Orderable orderable = Orderable.class.cast( attributeSource ); - if ( orderable.isOrdered() ) { - // todo : handle setting ordering - } + if ( !properties.contains( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER ) ) { + properties.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, nameNormalizer ); } + rootEntityBinding.getHierarchyDetails().getEntityIdentifier().createIdentifierGenerator( identifierGeneratorFactory, + properties ); } - private PluralAttributeElementNature convert(org.hibernate.metamodel.spi.source.PluralAttributeElementNature pluralAttributeElementNature) { - return PluralAttributeElementNature.valueOf( pluralAttributeElementNature.name() ); - } - - private EntityBinding getEntityBinding(String entityName) { - // Check if binding has already been created - EntityBinding binding = metadata.getEntityBinding( entityName ); - if ( binding == null ) { - // Find appropriate source to create binding - EntitySource source = sourcesByName.get( entityName ); - // Get super entity binding (creating it if necessary using recursive call to this method) - EntityBinding superBinding = source instanceof SubclassEntitySource - ? getEntityBinding( ( ( SubclassEntitySource ) source ).superclassEntitySource().getEntityName() ) - : null; - // Create entity binding - binding = createEntityBinding( source, superBinding ); - // Create entity binding's sub-entity bindings - processHierarchySubEntities( source, binding ); - } - return binding; - } - - private void resolveToOneInformation(ToOneAttributeSource attributeSource, ManyToOneAttributeBinding attributeBinding) { - final String referencedEntityName = attributeSource.getReferencedEntityName() != null - ? attributeSource.getReferencedEntityName() - : attributeBinding.getAttribute().getSingularAttributeType().getClassName(); - attributeBinding.setReferencedEntityName( referencedEntityName ); - // todo : we should consider basing references on columns instead of property-ref, which would require a resolution (later) of property-ref to column names - attributeBinding.setReferencedAttributeName( attributeSource.getReferencedEntityAttributeName() ); - - attributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() ); - attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); - attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); - } - - private MetaAttributeContext buildMetaAttributeContext(EntitySource entitySource) { - return buildMetaAttributeContext( - entitySource.metaAttributes(), - true, - currentBindingContext.getMetadataImplementor().getGlobalMetaAttributeContext() - ); - } - - private static MetaAttributeContext buildMetaAttributeContext( - Iterable metaAttributeSources, - MetaAttributeContext parentContext) { - return buildMetaAttributeContext( metaAttributeSources, false, parentContext ); + private MetaAttributeContext createMetaAttributeContext( final AttributeBindingContainer attributeBindingContainer, + final AttributeSource attributeSource ) { + return createMetaAttributeContext( attributeSource.metaAttributes(), + false, + attributeBindingContainer.getMetaAttributeContext() ); } - private static MetaAttributeContext buildMetaAttributeContext( - Iterable metaAttributeSources, - boolean onlyInheritable, - MetaAttributeContext parentContext) { + private MetaAttributeContext createMetaAttributeContext( final Iterable< MetaAttributeSource > metaAttributeSources, + final boolean onlyInheritable, + final MetaAttributeContext parentContext ) { final MetaAttributeContext subContext = new MetaAttributeContext( parentContext ); - - for ( MetaAttributeSource metaAttributeSource : metaAttributeSources ) { - if ( onlyInheritable & !metaAttributeSource.isInheritable() ) { + for ( final MetaAttributeSource metaAttributeSource : metaAttributeSources ) { + if ( onlyInheritable && !metaAttributeSource.isInheritable() ) { continue; } - final String name = metaAttributeSource.getName(); - final MetaAttribute inheritedMetaAttribute = parentContext.getMetaAttribute( name ); MetaAttribute metaAttribute = subContext.getLocalMetaAttribute( name ); - if ( metaAttribute == null || metaAttribute == inheritedMetaAttribute ) { + if ( metaAttribute == null || metaAttribute == parentContext.getMetaAttribute( name ) ) { metaAttribute = new MetaAttribute( name ); subContext.add( metaAttribute ); } metaAttribute.addValue( metaAttributeSource.getValue() ); } - return subContext; } - // Relational ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - private void bindPrimaryTable(EntitySource entitySource, final EntityBinding entityBinding) { - final TableSpecificationSource tableSpecificationSource = entitySource.getPrimaryTable(); - if ( TableSource.class.isInstance( tableSpecificationSource ) ) { - final Table table = createTable( - (TableSource) tableSpecificationSource, - new InferredNamingStrategy() { - @Override - public String inferredTableName() { - return currentBindingContext.getNamingStrategy() - .classToTableName( entityBinding.getEntity().getClassName() ); - } - } - ); - entityBinding.setPrimaryTable( table ); - // todo : ugh! - entityBinding.setPrimaryTableName( table.getTableName().getName() ); - } - else { - entityBinding.setPrimaryTable( createInLineView( (InLineViewSource) tableSpecificationSource ) ); - } - } - - private InLineView createInLineView(InLineViewSource inLineViewSource) { - final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName( - inLineViewSource.getExplicitSchemaName(), - inLineViewSource.getExplicitCatalogName(), - currentBindingContext - ); - final Identifier logicalName = Identifier.toIdentifier( inLineViewSource.getLogicalName() ); - return currentBindingContext.getMetadataImplementor() - .getDatabase() - .locateSchema( databaseSchemaName ) - .createInLineView( logicalName, inLineViewSource.getSelectStatement() ); - } - - private static interface InferredNamingStrategy { - public String inferredTableName(); + private SingularAttribute createSingularAttribute( final AttributeBindingContainer attributeBindingContainer, + final SingularAttributeSource attributeSource ) { + return attributeSource.isVirtualAttribute() + ? attributeBindingContainer.getAttributeContainer().createVirtualSingularAttribute( attributeSource.getName() ) + : attributeBindingContainer.getAttributeContainer().createSingularAttribute( attributeSource.getName() ); } - private Table createTable(TableSource tableSource, InferredNamingStrategy namingStrategy) { - String explicitTableNameString = tableSource.getExplicitTableName(); - if ( explicitTableNameString == null ) { - explicitTableNameString = namingStrategy.inferredTableName(); - } - explicitTableNameString = quoteIdentifier( explicitTableNameString ); - final Identifier logicalName = Identifier.toIdentifier( explicitTableNameString ); - - explicitTableNameString = currentBindingContext.getNamingStrategy().tableName( explicitTableNameString ); - explicitTableNameString = quoteIdentifier( explicitTableNameString ); - final Identifier physicalName = Identifier.toIdentifier( explicitTableNameString ); - - final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName( - tableSource.getExplicitSchemaName(), - tableSource.getExplicitCatalogName(), - currentBindingContext - ); - - Table table = currentBindingContext.getMetadataImplementor() - .getDatabase() - .locateSchema( databaseSchemaName ) - .locateTable( logicalName ); - if ( table == null ) { - table = currentBindingContext.getMetadataImplementor() - .getDatabase() - .locateSchema( databaseSchemaName ) - .createTable( logicalName, physicalName ); - } - return table; - } - - private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) { - final TableSpecification primaryEntityTable = entityBinding.getPrimaryTable(); - - for ( SecondaryTableSource secondaryTableSource : entitySource.getSecondaryTables() ) { - final TableSpecification secondaryTable; - final TableSpecificationSource source = secondaryTableSource.getTableSource(); - if ( TableSource.class.isInstance( source ) ) { - secondaryTable = createTable( - (TableSource) source, - new InferredNamingStrategy() { - @Override - public String inferredTableName() { - throw new MappingException( - "Secondary table must specify explicit name", - currentBindingContext.getOrigin() - ); - } - } - ); - } - else { - secondaryTable = createInLineView( (InLineViewSource) source ); - } - - // todo : really need a concept like SecondaryTableSource in the binding model as well - // so that EntityBinding can know the proper foreign key to use to build SQL statements. - - ForeignKey foreignKey = null; - if ( secondaryTableSource.getForeignKeyName() != null ) { - foreignKey = secondaryTable.locateForeignKey( secondaryTableSource.getForeignKeyName() ); - if ( foreignKey == null ) { - foreignKey = secondaryTable.createForeignKey( - primaryEntityTable, - secondaryTableSource.getForeignKeyName() - ); + private TableSpecification createTable( final TableSpecificationSource tableSpecSource, + final DefaultNamingStrategy defaultNamingStrategy ) { + final LocalBindingContext bindingContext = bindingContexts.peek(); + final MappingDefaults mappingDefaults = bindingContext.getMappingDefaults(); + final Schema.Name schemaName = + new Schema.Name( createIdentifier( tableSpecSource.getExplicitSchemaName(), mappingDefaults.getSchemaName() ), + createIdentifier( tableSpecSource.getExplicitCatalogName(), mappingDefaults.getCatalogName() ) ); + final Schema schema = metadata.getDatabase().locateSchema( schemaName ); + if ( tableSpecSource instanceof TableSource ) { + final TableSource tableSource = ( TableSource ) tableSpecSource; + String tableName = tableSource.getExplicitTableName(); + if ( tableName == null ) { + if ( defaultNamingStrategy == null ) { + throw new MappingException( "An explicit name must be specified for the table", bindingContext.getOrigin() ); } + tableName = defaultNamingStrategy.defaultName(); } - else { - // for now lets assume we have to create it, but eventually we should look through the - // candidate foreign keys referencing primary table also... - foreignKey = secondaryTable.createForeignKey( primaryEntityTable, null ); - } - - for ( PrimaryKeyJoinColumnSource joinColumnSource : secondaryTableSource.getJoinColumns() ) { - // todo : currently we only support columns here, not formulas - // todo : apply naming strategy to infer missing column name - Column fkColumn = secondaryTable.locateColumn( joinColumnSource.getColumnName() ); - if ( fkColumn == null ) { - fkColumn = secondaryTable.createColumn( joinColumnSource.getColumnName() ); - if ( joinColumnSource.getColumnDefinition() != null ) { - fkColumn.setSqlType( joinColumnSource.getColumnDefinition() ); - } - } - if ( joinColumnSource.getReferencedColumnName() != null ) { - final Column referencedColumn = primaryEntityTable.locateColumn( - joinColumnSource.getReferencedColumnName() - ); - foreignKey.addColumnMapping( fkColumn, referencedColumn ); - } - else { - foreignKey.addColumn( fkColumn ); - } - } - - entityBinding.addSecondaryTable( new SecondaryTable( secondaryTable, foreignKey ) ); - } + tableName = quotedIdentifier( tableName ); + final Identifier logicalTableId = Identifier.toIdentifier( tableName ); + tableName = quotedIdentifier( bindingContext.getNamingStrategy().tableName( tableName ) ); + final Identifier physicalTableId = Identifier.toIdentifier( tableName ); + System.out.println( "createTable: table = " + logicalTableId ); + final Table table = schema.locateTable( logicalTableId ); + return ( table == null ? schema.createTable( logicalTableId, physicalTableId ) : table ); + } + final InLineViewSource inLineViewSource = ( InLineViewSource ) tableSpecSource; + System.out.println( "createTable: inLineView = " + inLineViewSource.getLogicalName() ); + return schema.createInLineView( Identifier.toIdentifier( inLineViewSource.getLogicalName() ), + inLineViewSource.getSelectStatement() ); } - private void bindTableUniqueConstraints(EntitySource entitySource, EntityBinding entityBinding) { - for ( ConstraintSource constraintSource : entitySource.getConstraints() ) { - if ( constraintSource instanceof UniqueConstraintSource ) { - TableSpecification table = entityBinding.locateTable( constraintSource.getTableName() ); - if ( table == null ) { - // throw exception !? - } - String constraintName = constraintSource.name(); - if ( constraintName == null ) { - // create a default name - } - - UniqueKey uniqueKey = table.getOrCreateUniqueKey( constraintName ); - for ( String columnName : constraintSource.columnNames() ) { - uniqueKey.addColumn( table.locateOrCreateColumn( quoteIdentifier( columnName ) ) ); - } - } + private EntityBinding entityBinding( final String entityName ) { + System.out.println( "getEntityBinding( " + entityName + " )" ); + // Check if binding has already been created + EntityBinding entityBinding = metadata.getEntityBinding( entityName ); + if ( entityBinding == null ) { + // Find appropriate source to create binding + final EntitySource entitySource = entitySourcesByName.get( entityName ); + // Get super entity binding (creating it if necessary using recursive call to this method) + final EntityBinding superEntityBinding = + entitySource instanceof SubclassEntitySource + ? entityBinding( ( ( SubclassEntitySource ) entitySource ).superclassEntitySource().getEntityName() ) + : null; + // Create entity binding + entityBinding = + superEntityBinding == null + ? bindEntities( entityHierarchiesByRootEntitySource.get( entitySource ) ) + : bindEntity( entitySource, superEntityBinding ); } + return entityBinding; } - private List createSimpleRelationalValues( - RelationalValueSourceContainer relationalValueSourceContainer, - AttributeBindingContainer attributeBindingContainer, - Attribute attribute, - TableSpecification defaultTable) { - - List valueBindings = new ArrayList(); - - if ( !relationalValueSourceContainer.relationalValueSources().isEmpty() ) { - for ( RelationalValueSource valueSource : relationalValueSourceContainer.relationalValueSources() ) { - TableSpecification resolvedTable = defaultTable; - if ( valueSource.getContainingTableName() != null ) { - resolvedTable = attributeBindingContainer - .seekEntityBinding() - .locateTable( valueSource.getContainingTableName() ); - } - if ( ColumnSource.class.isInstance( valueSource ) ) { - final ColumnSource columnSource = ColumnSource.class.cast( valueSource ); - final Column column = - makeColumn( - columnSource, - relationalValueSourceContainer, - resolvedTable, - attribute.getName(), - true - ); - valueBindings.add( - new RelationalValueBinding( - column, - decode( columnSource.isIncludedInInsert(), relationalValueSourceContainer.areValuesIncludedInInsertByDefault() ), - decode( - columnSource.isIncludedInUpdate(), - relationalValueSourceContainer.areValuesIncludedInUpdateByDefault() - ) - ) - ); - } - else { - valueBindings.add( - new RelationalValueBinding( - makeDerivedValue( ( (DerivedValueSource) valueSource ), resolvedTable ) - ) - ); - } - } + private void mapSourcesByName( final EntitySource entitySource ) { + entitySourcesByName.put( entitySource.getEntityName(), entitySource ); + for ( final AttributeSource attributeSource : entitySource.attributeSources() ) { + attributeSourcesByName.put( attributeSource.getName(), attributeSource ); } - else { - String name = metadata.getOptions() - .getNamingStrategy() - .propertyToColumnName( attribute.getName() ); - name = quoteIdentifier( name ); - Column column = defaultTable.locateOrCreateColumn( name ); - column.setNullable( relationalValueSourceContainer.areValuesNullableByDefault() ); - valueBindings.add( new RelationalValueBinding( column ) ); + for ( final SubclassEntitySource subclassEntitySource : entitySource.subclassEntitySources() ) { + mapSourcesByName( subclassEntitySource ); } - return valueBindings; } - private String quoteIdentifier(String string) { - return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( string ) : string; + private PluralAttributeElementNature pluralAttributeElementNature( final PluralAttributeSource attributeSource ) { + return PluralAttributeElementNature.valueOf( attributeSource.getElementSource().getNature().name() ); } - private Value makeRelationalValue( - TableSpecification table, - RelationalValueSource valueSource, - ColumnBindingDefaults columnBindingDefaults, - Attribute attribute) { - if ( ColumnSource.class.isInstance( valueSource ) ) { - final ColumnSource columnSource = ColumnSource.class.cast( valueSource ); - return makeColumn( - columnSource, - columnBindingDefaults, - table, - attribute.getName(), - true - ); + private SingularAttributeBinding pluralAttributeKeyBinding( final AttributeBindingContainer attributeBindingContainer, + final PluralAttributeSource attributeSource ) { + final EntityBinding entityBinding = attributeBindingContainer.seekEntityBinding(); + final String referencedAttributeName = attributeSource.getKeySource().getReferencedEntityAttributeName(); + final AttributeBinding referencedAttributeBinding = + referencedAttributeName == null + ? entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() + : entityBinding.locateAttributeBinding( referencedAttributeName ); + if ( referencedAttributeBinding == null ) { + throw new MappingException( "Plural atttribute key references an attribute binding that does not exist: " + + referencedAttributeBinding, bindingContexts.peek().getOrigin() ); } - else { - return makeDerivedValue( (DerivedValueSource) valueSource, table ); + if ( !referencedAttributeBinding.getAttribute().isSingular() ) { + throw new MappingException( "Plural atttribute key references a plural attribute; it must be plural: " + + referencedAttributeName, bindingContexts.peek().getOrigin() ); } + return ( SingularAttributeBinding ) referencedAttributeBinding; } - private Column makeColumn( - ColumnSource columnSource, - ColumnBindingDefaults columnBindingDefaults, - TableSpecification table, - String defaultName, - boolean isDefaultAttributeName) { - if ( columnSource.getName() == null && defaultName == null ) { - throw new MappingException( - "Cannot resolve name for column because the no name was specified and default name is null.", - currentBindingContext.getOrigin() - ); - } - String name; - if ( columnSource.getName() != null ) { - name = metadata.getOptions().getNamingStrategy().columnName( columnSource.getName() ); - } - else if ( isDefaultAttributeName ) { - name = metadata.getOptions().getNamingStrategy().propertyToColumnName( defaultName ); - } - else { - name = metadata.getOptions().getNamingStrategy().columnName( defaultName ); - } - String resolvedColumnName = quoteIdentifier( name ); - final Column column = table.locateOrCreateColumn( resolvedColumnName ); - column.setNullable( - decode( columnSource.isNullable(), columnBindingDefaults.areValuesNullableByDefault() ) - ); - column.setDefaultValue( columnSource.getDefaultValue() ); - column.setSqlType( columnSource.getSqlType() ); - column.setSize( columnSource.getSize() ); - column.setJdbcDataType( columnSource.getDatatype() ); - column.setReadFragment( columnSource.getReadFragment() ); - column.setWriteFragment( columnSource.getWriteFragment() ); - column.setUnique( columnSource.isUnique() ); - column.setCheckCondition( columnSource.getCheckCondition() ); - column.setComment( columnSource.getComment() ); - return column; + private String propertyAccessorName( final AttributeSource attributeSource ) { + return attributeSource.getPropertyAccessorName() == null ? bindingContexts.peek().getMappingDefaults().getPropertyAccessorName() + : attributeSource.getPropertyAccessorName(); } - private boolean decode(TruthValue truthValue, boolean defaultValue) { - switch ( truthValue ) { - case FALSE: { - return false; - } - case TRUE: { - return true; - } - default: { - return defaultValue; + private String quotedIdentifier( final String name ) { + return bindingContexts.peek().isGloballyQuotedIdentifiers() ? StringHelper.quote( name ) : name; + } + + private void resolveHibernateResolvedType( final HibernateTypeDescriptor hibernateTypeDescriptor, + final String typeName, + final AbstractValue value ) { + final Properties typeProperties = new Properties(); + typeProperties.putAll( hibernateTypeDescriptor.getTypeParameters() ); + final Type resolvedType = metadata.getTypeResolver().heuristicType( typeName, typeProperties ); + // Configure relational value JDBC type from Hibernate type descriptor now that its configured + if ( resolvedType != null ) { + hibernateTypeDescriptor.setResolvedTypeMapping( resolvedType ); + if ( hibernateTypeDescriptor.getJavaTypeName() == null ) { + hibernateTypeDescriptor.setJavaTypeName( resolvedType.getReturnedClass().getName() ); } + value.setJdbcDataType( new JdbcDataType( resolvedType.sqlTypes( metadata )[ 0 ], resolvedType.getName(), + resolvedType.getReturnedClass() ) ); } } - private DerivedValue makeDerivedValue(DerivedValueSource derivedValueSource, TableSpecification table) { - return table.locateOrCreateDerivedValue( derivedValueSource.getExpression() ); + private boolean toBoolean( final TruthValue truthValue, + final boolean truthValueDefault ) { + if ( truthValue == TruthValue.TRUE ) { + return true; + } + if ( truthValue == TruthValue.FALSE ) { + return false; + } + return truthValueDefault; } - private void processFetchProfiles(EntitySource entitySource, EntityBinding entityBinding) { - // todo : process the entity-local fetch-profile declaration - } + private interface DefaultNamingStrategy { + String defaultName(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java index 0c77c7a2d772..ef206f80a072 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/HibernateTypeHelper.java @@ -102,17 +102,16 @@ public class HibernateTypeHelper { private static final Logger log = Logger.getLogger( HibernateTypeHelper.class ); private final Binder binder; + private final MetadataImplementor metadata; - public HibernateTypeHelper(Binder binder) { + public HibernateTypeHelper( Binder binder, + MetadataImplementor metadata ) { this.binder = binder; + this.metadata = metadata; } private org.hibernate.metamodel.spi.domain.Type makeJavaType(String name) { - return binder.getCurrentBindingContext().makeJavaType( name ); - } - - private MetadataImplementor metadata() { - return binder.getMetadata(); + return binder.bindingContext().makeJavaType( name ); } public void bindSingularAttributeTypeInformation( @@ -183,7 +182,7 @@ private void processPluralAttributeKeyTypeInformation(PluralAttributeKeyBinding // TODO: not sure about the following... pluralAttributeKeyTypeDescriptor.setToOne( referencedTypeDescriptor.isToOne() ); pluralAttributeKeyTypeDescriptor.getTypeParameters().putAll( referencedTypeDescriptor.getTypeParameters() ); - + processPluralAttributeKeyInformation( keyBinding ); } @@ -215,7 +214,7 @@ private void processPluralAttributeKeyInformation(PluralAttributeKeyBinding keyB } } } - + private Class determineJavaType(final SingularAttribute attribute) { try { final Class ownerClass = attribute.getAttributeContainer().getClassReference(); @@ -262,7 +261,7 @@ private void bindHibernateTypeInformation( HibernateTypeDescriptor hibernateTypeDescriptor) { final String explicitTypeName = typeSource.getName(); if ( explicitTypeName != null ) { - final TypeDefinition typeDefinition = metadata().getTypeDefinition( explicitTypeName ); + final TypeDefinition typeDefinition = metadata.getTypeDefinition( explicitTypeName ); if ( typeDefinition != null ) { hibernateTypeDescriptor.setExplicitTypeName( typeDefinition.getTypeImplementorClass().getName() ); hibernateTypeDescriptor.getTypeParameters().putAll( typeDefinition.getParameters() ); @@ -318,7 +317,7 @@ public Type determineHibernateTypeFromDescriptor(HibernateTypeDescriptor hiberna private Type getHeuristicType(String typeName, Properties typeParameters) { if ( typeName != null ) { try { - return metadata().getTypeResolver().heuristicType( typeName, typeParameters ); + return metadata.getTypeResolver().heuristicType( typeName, typeParameters ); } catch (Exception ignore) { } @@ -452,7 +451,7 @@ public void pushHibernateTypeInformationDown(Type resolvedHibernateType, Value v if ( AbstractValue.class.isInstance( value ) ) { ( (AbstractValue) value ).setJdbcDataType( new JdbcDataType( - resolvedHibernateType.sqlTypes( metadata() )[0], + resolvedHibernateType.sqlTypes( metadata )[0], resolvedHibernateType.getName(), resolvedHibernateType.getReturnedClass() ) @@ -480,7 +479,7 @@ private void processCollectionTypeInformation(PluralAttributeBinding attributeBi String typeName = attributeBinding.getHibernateTypeDescriptor().getExplicitTypeName(); if ( typeName != null ) { resolvedType = - metadata().getTypeResolver() + metadata.getTypeResolver() .getTypeFactory() .customCollection( typeName, @@ -500,7 +499,7 @@ private void processCollectionTypeInformation(PluralAttributeBinding attributeBi } private Type determineHibernateTypeFromCollectionType(PluralAttributeBinding attributeBinding) { - final TypeFactory typeFactory = metadata().getTypeResolver().getTypeFactory(); + final TypeFactory typeFactory = metadata.getTypeResolver().getTypeFactory(); switch ( attributeBinding.getAttribute().getNature() ) { case SET: { return typeFactory.set(