package org.hibernate.metamodel.source.binder;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.beans.BeanInfoHelper;
import org.hibernate.metamodel.binding.AbstractPluralAttributeBinding;
import org.hibernate.metamodel.binding.AttributeBinding;
import org.hibernate.metamodel.binding.AttributeBindingContainer;
import org.hibernate.metamodel.binding.BasicAttributeBinding;
import org.hibernate.metamodel.binding.BasicCollectionElement;
import org.hibernate.metamodel.binding.CollectionElementNature;
import org.hibernate.metamodel.binding.CollectionLaziness;
import org.hibernate.metamodel.binding.ComponentAttributeBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityDiscriminator;
import org.hibernate.metamodel.binding.HibernateTypeDescriptor;
import org.hibernate.metamodel.binding.IdGenerator;
import org.hibernate.metamodel.binding.InheritanceType;
import org.hibernate.metamodel.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.binding.MetaAttribute;
import org.hibernate.metamodel.binding.SimpleValueBinding;
import org.hibernate.metamodel.binding.SingularAttributeBinding;
import org.hibernate.metamodel.binding.TypeDef;
import org.hibernate.metamodel.domain.Component;
import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.domain.SingularAttribute;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.DerivedValue;
import org.hibernate.metamodel.relational.Identifier;
import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.source.LocalBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.MetaAttributeContext;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.source.hbm.Helper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.tuple.entity.EntityTuplizer;
public class Binder {
private final MetadataImplementor metadata;
private final List<String> processedEntityNames;
private InheritanceType currentInheritanceType;
private EntityMode currentHierarchyEntityMode;
private LocalBindingContext currentBindingContext;
public Binder(MetadataImplementor metadata, List<String> processedEntityNames) {
this.metadata = metadata;
this.processedEntityNames = processedEntityNames;
}
public void processEntityHierarchy(EntityHierarchy entityHierarchy) {
currentInheritanceType = entityHierarchy.getHierarchyInheritanceType();
EntityBinding rootEntityBinding = createEntityBinding( entityHierarchy.getRootEntitySource(), null );
if ( currentInheritanceType != InheritanceType.NO_INHERITANCE ) {
processHierarchySubEntities( entityHierarchy.getRootEntitySource(), rootEntityBinding );
}
currentHierarchyEntityMode = null;
}
private void processHierarchySubEntities(SubclassEntityContainer subclassEntitySource, EntityBinding superEntityBinding) {
for ( SubclassEntitySource subEntity : subclassEntitySource.subclassEntitySources() ) {
EntityBinding entityBinding = createEntityBinding( subEntity, superEntityBinding );
processHierarchySubEntities( subEntity, entityBinding );
}
}
private EntityBinding createEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
if ( processedEntityNames.contains( entitySource.getEntityName() ) ) {
return metadata.getEntityBinding( entitySource.getEntityName() );
}
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 EntityBinding doCreateEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
final EntityBinding entityBinding = createBasicEntityBinding( entitySource, superEntityBinding );
bindSecondaryTables( entitySource, entityBinding );
bindAttributes( entitySource, entityBinding );
bindTableUniqueConstraints( entitySource, entityBinding );
return entityBinding;
}
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:
throw new AssertionFailure( "Internal condition failure" );
}
}
}
private EntityBinding makeRootEntityBinding(RootEntitySource entitySource) {
currentHierarchyEntityMode = entitySource.getEntityMode();
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 );
}
else if ( entitySource.isLazy() ) {
entityBinding.setProxyInterfaceType( entityBinding.getEntity().getClassReferenceUnresolved() );
entityBinding.setLazy( true );
}
}
else {
entityBinding.setProxyInterfaceType( null );
entityBinding.setLazy( entitySource.isLazy() );
}
final String customTuplizerClassName = entitySource.getCustomTuplizerClassName();
if ( customTuplizerClassName != null ) {
entityBinding.setCustomEntityTuplizerClass(
currentBindingContext.<EntityTuplizer>locateClassByName(
customTuplizerClassName
)
);
}
final String customPersisterClassName = entitySource.getCustomPersisterClassName();
if ( customPersisterClassName != null ) {
entityBinding.setCustomEntityPersisterClass(
currentBindingContext.<EntityPersister>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() );
}
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 );
return entityBinding;
}
private EntityBinding makeUnionedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) {
final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding );
bindPrimaryTable( entitySource, entityBinding );
return entityBinding;
}
private void bindIdentifier(RootEntitySource entitySource, EntityBinding entityBinding) {
if ( entitySource.getIdentifierSource() == null ) {
throw new AssertionFailure( "Expecting identifier information on root entity descriptor" );
}
switch ( entitySource.getIdentifierSource().getNature() ) {
case SIMPLE: {
bindSimpleIdentifier( (SimpleIdentifierSource) entitySource.getIdentifierSource(), entityBinding );
break;
}
case AGGREGATED_COMPOSITE: {
break;
}
case COMPOSITE: {
break;
}
}
}
private void bindSimpleIdentifier(SimpleIdentifierSource identifierSource, EntityBinding entityBinding) {
final BasicAttributeBinding idAttributeBinding = doBasicSingularAttributeBindingCreation(
identifierSource.getIdentifierAttributeSource(), entityBinding
);
entityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding );
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
Map<String, String> params = new HashMap<String, String>();
params.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
entityBinding.getHierarchyDetails()
.getEntityIdentifier()
.setIdGenerator( generator );
final org.hibernate.metamodel.relational.Value relationalValue = idAttributeBinding.getValue();
if ( SimpleValue.class.isInstance( relationalValue ) ) {
if ( !Column.class.isInstance( relationalValue ) ) {
throw new AssertionFailure( "Simple-id was not a column." );
}
entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( relationalValue ) );
}
else {
for ( SimpleValue subValue : ( (Tuple) relationalValue ).values() ) {
if ( Column.class.isInstance( subValue ) ) {
entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( subValue ) );
}
}
}
}
private void bindVersion(EntityBinding entityBinding, RootEntitySource entitySource) {
final SingularAttributeSource versioningAttributeSource = entitySource.getVersioningAttributeSource();
if ( versioningAttributeSource == null ) {
return;
}
BasicAttributeBinding attributeBinding = doBasicSingularAttributeBindingCreation(
versioningAttributeSource, entityBinding
);
entityBinding.getHierarchyDetails().setVersioningAttributeBinding( attributeBinding );
}
private void bindDiscriminator(RootEntitySource entitySource, EntityBinding entityBinding) {
final DiscriminatorSource discriminatorSource = entitySource.getDiscriminatorSource();
if ( discriminatorSource == null ) {
return;
}
EntityDiscriminator discriminator = new EntityDiscriminator();
SimpleValue relationalValue = makeSimpleValue(
entityBinding,
discriminatorSource.getDiscriminatorRelationalValueSource()
);
discriminator.setBoundValue( relationalValue );
discriminator.getExplicitHibernateTypeDescriptor().setExplicitTypeName(
discriminatorSource.getExplicitHibernateTypeName() != null
? discriminatorSource.getExplicitHibernateTypeName()
: "string"
);
discriminator.setInserted( discriminatorSource.isInserted() );
discriminator.setForced( discriminatorSource.isForced() );
entityBinding.getHierarchyDetails().setEntityDiscriminator( discriminator );
entityBinding.setDiscriminatorMatchValue( entitySource.getDiscriminatorMatchValue() );
}
private void bindDiscriminatorValue(SubclassEntitySource entitySource, EntityBinding entityBinding) {
final String discriminatorValue = entitySource.getDiscriminatorMatchValue();
if ( discriminatorValue == null ) {
return;
}
entityBinding.setDiscriminatorMatchValue( discriminatorValue );
}
private void bindAttributes(AttributeSourceContainer attributeSourceContainer, AttributeBindingContainer attributeBindingContainer) {
for ( AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) {
if ( attributeSource.isSingular() ) {
final SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource;
if ( singularAttributeSource.getNature() == SingularAttributeNature.COMPONENT ) {
bindComponent( (ComponentAttributeSource) singularAttributeSource, attributeBindingContainer );
}
else {
doBasicSingularAttributeBindingCreation( singularAttributeSource, attributeBindingContainer );
}
}
else {
bindPersistentCollection( (PluralAttributeSource) attributeSource, attributeBindingContainer );
}
}
}
private void bindComponent(ComponentAttributeSource attributeSource, AttributeBindingContainer container) {
final String attributeName = attributeSource.getName();
SingularAttribute attribute = container.getAttributeContainer().locateComponentAttribute( attributeName );
if ( attribute == null ) {
final Component component = new Component(
attributeSource.getPath(),
attributeSource.getClassName(),
attributeSource.getClassReference(),
null
);
attribute = container.getAttributeContainer().createComponentAttribute( attributeName, component );
}
ComponentAttributeBinding componentAttributeBinding = container.makeComponentAttributeBinding( attribute );
if ( StringHelper.isNotEmpty( attributeSource.getParentReferenceAttributeName() ) ) {
final SingularAttribute parentReferenceAttribute =
componentAttributeBinding.getComponent()
.createSingularAttribute( attributeSource.getParentReferenceAttributeName() );
componentAttributeBinding.setParentReference( parentReferenceAttribute );
}
componentAttributeBinding.setMetaAttributeContext(
buildMetaAttributeContext( attributeSource.metaAttributes(), container.getMetaAttributeContext() )
);
bindAttributes( attributeSource, componentAttributeBinding );
}
private void bindPersistentCollection(PluralAttributeSource attributeSource, AttributeBindingContainer attributeBindingContainer) {
final PluralAttribute existingAttribute = attributeBindingContainer.getAttributeContainer()
.locatePluralAttribute( attributeSource.getName() );
final AbstractPluralAttributeBinding pluralAttributeBinding;
if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) {
final PluralAttribute attribute = existingAttribute != null
? existingAttribute
: attributeBindingContainer.getAttributeContainer().createBag( attributeSource.getName() );
pluralAttributeBinding = attributeBindingContainer.makeBagAttributeBinding(
attribute,
convert( attributeSource.getElementSource().getNature() )
);
}
else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SET ) {
final PluralAttribute attribute = existingAttribute != null
? existingAttribute
: attributeBindingContainer.getAttributeContainer().createSet( attributeSource.getName() );
pluralAttributeBinding = attributeBindingContainer.makeSetAttributeBinding(
attribute,
convert( attributeSource.getElementSource().getNature() )
);
}
else {
throw new NotYetImplementedException( "Collections other than bag and set not yet implemented :(" );
}
doBasicPluralAttributeBinding( attributeSource, pluralAttributeBinding );
bindCollectionTable( attributeSource, pluralAttributeBinding );
bindSortingAndOrdering( attributeSource, pluralAttributeBinding );
bindCollectionKey( attributeSource, pluralAttributeBinding );
bindCollectionElement( attributeSource, pluralAttributeBinding );
bindCollectionIndex( attributeSource, pluralAttributeBinding );
metadata.addCollection( pluralAttributeBinding );
}
private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) {
binding.setFetchTiming( source.getFetchTiming() );
binding.setFetchStyle( source.getFetchStyle() );
binding.setCascadeStyles( source.getCascadeStyles() );
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.setCollectionPersisterClass(
currentBindingContext.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
);
}
if ( source.getCustomPersisterClassName() != null ) {
binding.setCollectionPersisterClass(
metadata.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
);
}
binding.setCustomLoaderName( source.getCustomLoaderName() );
binding.setCustomSqlInsert( source.getCustomSqlInsert() );
binding.setCustomSqlUpdate( source.getCustomSqlUpdate() );
binding.setCustomSqlDelete( source.getCustomSqlDelete() );
binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() );
binding.setMetaAttributeContext(
buildMetaAttributeContext(
source.metaAttributes(),
binding.getContainer().getMetaAttributeContext()
)
);
doBasicAttributeBinding( source, binding );
}
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(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
if ( attributeSource.getElementSource().getNature() == PluralAttributeElementNature.ONE_TO_MANY ) {
return;
}
final Schema.Name schemaName = Helper.determineDatabaseSchemaName(
attributeSource.getExplicitSchemaName(),
attributeSource.getExplicitCatalogName(),
currentBindingContext
);
final Schema schema = metadata.getDatabase().locateSchema( schemaName );
final String tableName = attributeSource.getExplicitCollectionTableName();
if ( StringHelper.isNotEmpty( tableName ) ) {
final Identifier tableIdentifier = Identifier.toIdentifier(
currentBindingContext.getNamingStrategy().tableName( tableName )
);
Table collectionTable = schema.locateTable( tableIdentifier );
if ( collectionTable == null ) {
collectionTable = schema.createTable( tableIdentifier );
}
pluralAttributeBinding.setCollectionTable( collectionTable );
}
else {
final EntityBinding owner = pluralAttributeBinding.getContainer().seekEntityBinding();
final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() )
? Table.class.cast( owner.getPrimaryTable() ).getTableName().getName()
: null;
String collectionTableName = currentBindingContext.getNamingStrategy().collectionTableName(
owner.getEntity().getName(),
ownerTableLogicalName,
null,
null,
pluralAttributeBinding.getContainer().getPathBase() + '.' + attributeSource.getName()
);
collectionTableName = quoteIdentifier( collectionTableName );
pluralAttributeBinding.setCollectionTable(
schema.locateOrCreateTable(
Identifier.toIdentifier(
collectionTableName
)
)
);
}
if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableComment() ) ) {
pluralAttributeBinding.getCollectionTable().addComment( attributeSource.getCollectionTableComment() );
}
if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) {
pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() );
}
pluralAttributeBinding.setWhere( attributeSource.getWhere() );
}
private void bindCollectionKey(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
pluralAttributeBinding.getCollectionKey().prepareForeignKey(
attributeSource.getKeySource().getExplicitForeignKeyName(),
null
);
pluralAttributeBinding.getCollectionKey().getForeignKey().setDeleteRule(
attributeSource.getKeySource().getOnDeleteAction()
);
}
private void bindCollectionElement(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
final PluralAttributeElementSource elementSource = attributeSource.getElementSource();
if ( elementSource.getNature() == PluralAttributeElementNature.BASIC ) {
final BasicPluralAttributeElementSource basicElementSource = (BasicPluralAttributeElementSource) elementSource;
final BasicCollectionElement basicCollectionElement = (BasicCollectionElement) pluralAttributeBinding.getCollectionElement();
resolveTypeInformation(
basicElementSource.getExplicitHibernateTypeSource(),
pluralAttributeBinding.getAttribute(),
basicCollectionElement
);
return;
}
throw new NotYetImplementedException(
String.format(
"Support for collection elements of type %s not yet implemented",
elementSource.getNature()
)
);
}
private void bindCollectionIndex(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
if ( attributeSource.getPluralAttributeNature() != PluralAttributeNature.LIST
&& attributeSource.getPluralAttributeNature() != PluralAttributeNature.MAP ) {
return;
}
throw new NotYetImplementedException();
}
private void bindSortingAndOrdering(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
if ( Sortable.class.isInstance( attributeSource ) ) {
final Sortable sortable = Sortable.class.cast( attributeSource );
if ( sortable.isSorted() ) {
return;
}
}
if ( Orderable.class.isInstance( attributeSource ) ) {
final Orderable orderable = Orderable.class.cast( attributeSource );
if ( orderable.isOrdered() ) {
}
}
}
private void doBasicAttributeBinding(AttributeSource attributeSource, AttributeBinding attributeBinding) {
attributeBinding.setPropertyAccessorName( attributeSource.getPropertyAccessorName() );
attributeBinding.setIncludedInOptimisticLocking( attributeSource.isIncludedInOptimisticLocking() );
}
private CollectionElementNature convert(PluralAttributeElementNature pluralAttributeElementNature) {
return CollectionElementNature.valueOf( pluralAttributeElementNature.name() );
}
private BasicAttributeBinding doBasicSingularAttributeBindingCreation(
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 BasicAttributeBinding attributeBinding;
if ( attributeSource.getNature() == SingularAttributeNature.BASIC ) {
attributeBinding = attributeBindingContainer.makeBasicAttributeBinding( attribute );
resolveTypeInformation( attributeSource.getTypeInformation(), attributeBinding );
}
else if ( attributeSource.getNature() == SingularAttributeNature.MANY_TO_ONE ) {
attributeBinding = attributeBindingContainer.makeManyToOneAttributeBinding( attribute );
resolveTypeInformation( attributeSource.getTypeInformation(), attributeBinding );
resolveToOneInformation(
(ToOneAttributeSource) attributeSource,
(ManyToOneAttributeBinding) attributeBinding
);
}
else {
throw new NotYetImplementedException();
}
attributeBinding.setGeneration( attributeSource.getGeneration() );
attributeBinding.setLazy( attributeSource.isLazy() );
attributeBinding.setIncludedInOptimisticLocking( attributeSource.isIncludedInOptimisticLocking() );
attributeBinding.setPropertyAccessorName(
Helper.getPropertyAccessorName(
attributeSource.getPropertyAccessorName(),
false,
currentBindingContext.getMappingDefaults().getPropertyAccessorName()
)
);
bindRelationalValues( attributeSource, attributeBinding );
attributeBinding.setMetaAttributeContext(
buildMetaAttributeContext(
attributeSource.metaAttributes(),
attributeBindingContainer.getMetaAttributeContext()
)
);
return attributeBinding;
}
private void resolveTypeInformation(ExplicitHibernateTypeSource typeSource, BasicAttributeBinding attributeBinding) {
final Class<?> attributeJavaType = determineJavaType( attributeBinding.getAttribute() );
if ( attributeJavaType != null ) {
attributeBinding.getAttribute()
.resolveType( currentBindingContext.makeJavaType( attributeJavaType.getName() ) );
}
resolveTypeInformation( typeSource, attributeBinding.getHibernateTypeDescriptor(), attributeJavaType );
}
private void resolveTypeInformation(
ExplicitHibernateTypeSource typeSource,
PluralAttribute attribute,
BasicCollectionElement collectionElement) {
final Class<?> attributeJavaType = determineJavaType( attribute );
resolveTypeInformation( typeSource, collectionElement.getHibernateTypeDescriptor(), attributeJavaType );
}
private void resolveTypeInformation(
ExplicitHibernateTypeSource typeSource,
HibernateTypeDescriptor hibernateTypeDescriptor,
Class<?> discoveredJavaType) {
if ( discoveredJavaType != null ) {
hibernateTypeDescriptor.setJavaTypeName( discoveredJavaType.getName() );
}
final String explicitTypeName = typeSource.getName();
if ( explicitTypeName != null ) {
final TypeDef typeDef = currentBindingContext.getMetadataImplementor()
.getTypeDefinition( explicitTypeName );
if ( typeDef != null ) {
hibernateTypeDescriptor.setExplicitTypeName( typeDef.getTypeClass() );
hibernateTypeDescriptor.getTypeParameters().putAll( typeDef.getParameters() );
}
else {
hibernateTypeDescriptor.setExplicitTypeName( explicitTypeName );
}
final Map<String, String> parameters = typeSource.getParameters();
if ( parameters != null ) {
hibernateTypeDescriptor.getTypeParameters().putAll( parameters );
}
}
else {
if ( discoveredJavaType == null ) {
}
}
}
private Class<?> determineJavaType(final SingularAttribute attribute) {
try {
final Class<?> ownerClass = attribute.getAttributeContainer().getClassReference();
AttributeJavaTypeDeterminerDelegate delegate = new AttributeJavaTypeDeterminerDelegate( attribute.getName() );
BeanInfoHelper.visitBeanInfo( ownerClass, delegate );
return delegate.javaType;
}
catch ( Exception ignore ) {
}
return null;
}
private Class<?> determineJavaType(PluralAttribute attribute) {
try {
final Class<?> ownerClass = attribute.getAttributeContainer().getClassReference();
PluralAttributeJavaTypeDeterminerDelegate delegate = new PluralAttributeJavaTypeDeterminerDelegate(
ownerClass,
attribute.getName()
);
BeanInfoHelper.visitBeanInfo( ownerClass, delegate );
return delegate.javaType;
}
catch ( Exception ignore ) {
}
return null;
}
private class PluralAttributeJavaTypeDeterminerDelegate implements BeanInfoHelper.BeanInfoDelegate {
private final Class<?> ownerClass;
private final String attributeName;
private Class<?> javaType = null;
private PluralAttributeJavaTypeDeterminerDelegate(Class<?> ownerClass, String attributeName) {
this.ownerClass = ownerClass;
this.attributeName = attributeName;
}
@Override
public void processBeanInfo(BeanInfo beanInfo) throws Exception {
for ( PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors() ) {
if ( propertyDescriptor.getName().equals( attributeName ) ) {
javaType = extractCollectionComponentType( beanInfo, propertyDescriptor );
break;
}
}
}
@SuppressWarnings( { "unchecked" })
private Class<?> (BeanInfo beanInfo, PropertyDescriptor propertyDescriptor) {
final java.lang.reflect.Type collectionAttributeType;
if ( propertyDescriptor.getReadMethod() != null ) {
collectionAttributeType = propertyDescriptor.getReadMethod().getGenericReturnType();
}
else if ( propertyDescriptor.getWriteMethod() != null ) {
collectionAttributeType = propertyDescriptor.getWriteMethod().getGenericParameterTypes()[0];
}
else {
try {
collectionAttributeType = ownerClass.getField( propertyDescriptor.getName() ).getGenericType();
}
catch ( Exception e ) {
return null;
}
}
if ( ParameterizedType.class.isInstance( collectionAttributeType ) ) {
final java.lang.reflect.Type[] types = ( (ParameterizedType) collectionAttributeType ).getActualTypeArguments();
if ( types == null ) {
return null;
}
else if ( types.length == 1 ) {
return (Class<?>) types[0];
}
else if ( types.length == 2 ) {
return (Class<?>) types[1];
}
}
return null;
}
}
private void resolveToOneInformation(ToOneAttributeSource attributeSource, ManyToOneAttributeBinding attributeBinding) {
final String referencedEntityName = attributeSource.getReferencedEntityName() != null
? attributeSource.getReferencedEntityName()
: attributeBinding.getAttribute().getSingularAttributeType().getClassName();
attributeBinding.setReferencedEntityName( referencedEntityName );
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<MetaAttributeSource> metaAttributeSources,
MetaAttributeContext parentContext) {
return buildMetaAttributeContext( metaAttributeSources, false, parentContext );
}
private static MetaAttributeContext buildMetaAttributeContext(
Iterable<MetaAttributeSource> metaAttributeSources,
boolean onlyInheritable,
MetaAttributeContext parentContext) {
final MetaAttributeContext subContext = new MetaAttributeContext( parentContext );
for ( 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 ) {
metaAttribute = new MetaAttribute( name );
subContext.add( metaAttribute );
}
metaAttribute.addValue( metaAttributeSource.getValue() );
}
return subContext;
}
private void bindPrimaryTable(EntitySource entitySource, EntityBinding entityBinding) {
final TableSource tableSource = entitySource.getPrimaryTable();
final Table table = createTable( entityBinding, tableSource );
entityBinding.setPrimaryTable( table );
entityBinding.setPrimaryTableName( table.getTableName().getName() );
}
private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) {
for ( TableSource secondaryTableSource : entitySource.getSecondaryTables() ) {
final Table table = createTable( entityBinding, secondaryTableSource );
entityBinding.addSecondaryTable( secondaryTableSource.getLogicalName(), table );
}
}
private Table createTable(EntityBinding entityBinding, TableSource tableSource) {
String tableName = tableSource.getExplicitTableName();
if ( StringHelper.isEmpty( tableName ) ) {
tableName = currentBindingContext.getNamingStrategy()
.classToTableName( entityBinding.getEntity().getClassName() );
}
else {
tableName = currentBindingContext.getNamingStrategy().tableName( tableName );
}
tableName = quoteIdentifier( tableName );
final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName(
tableSource.getExplicitSchemaName(),
tableSource.getExplicitCatalogName(),
currentBindingContext
);
return currentBindingContext.getMetadataImplementor()
.getDatabase()
.locateSchema( databaseSchemaName )
.locateOrCreateTable( Identifier.toIdentifier( tableName ) );
}
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 ) {
}
String constraintName = constraintSource.name();
if ( constraintName == null ) {
}
UniqueKey uniqueKey = table.getOrCreateUniqueKey( constraintName );
for ( String columnName : constraintSource.columnNames() ) {
uniqueKey.addColumn( table.locateOrCreateColumn( quoteIdentifier( columnName ) ) );
}
}
}
}
private void bindRelationalValues(
RelationalValueSourceContainer relationalValueSourceContainer,
SingularAttributeBinding attributeBinding) {
List<SimpleValueBinding> valueBindings = new ArrayList<SimpleValueBinding>();
if ( !relationalValueSourceContainer.relationalValueSources().isEmpty() ) {
for ( RelationalValueSource valueSource : relationalValueSourceContainer.relationalValueSources() ) {
final TableSpecification table = attributeBinding.getContainer()
.seekEntityBinding()
.locateTable( valueSource.getContainingTableName() );
if ( ColumnSource.class.isInstance( valueSource ) ) {
final ColumnSource columnSource = ColumnSource.class.cast( valueSource );
final Column column = makeColumn( (ColumnSource) valueSource, table );
valueBindings.add(
new SimpleValueBinding(
column,
columnSource.isIncludedInInsert(),
columnSource.isIncludedInUpdate()
)
);
}
else {
valueBindings.add(
new SimpleValueBinding(
makeDerivedValue( ( (DerivedValueSource) valueSource ), table )
)
);
}
}
}
else {
String name = metadata.getOptions()
.getNamingStrategy()
.propertyToColumnName( attributeBinding.getAttribute().getName() );
name = quoteIdentifier( name );
Column column = attributeBinding.getContainer()
.seekEntityBinding()
.getPrimaryTable()
.locateOrCreateColumn( name );
column.setNullable( relationalValueSourceContainer.areValuesNullableByDefault() );
valueBindings.add(
new SimpleValueBinding(
column,
relationalValueSourceContainer.areValuesIncludedInInsertByDefault(),
relationalValueSourceContainer.areValuesIncludedInUpdateByDefault()
)
);
}
attributeBinding.setSimpleValueBindings( valueBindings );
}
private String quoteIdentifier(String identifier) {
return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( identifier ) : identifier;
}
private SimpleValue makeSimpleValue(
EntityBinding entityBinding,
RelationalValueSource valueSource) {
final TableSpecification table = entityBinding.locateTable( valueSource.getContainingTableName() );
if ( ColumnSource.class.isInstance( valueSource ) ) {
return makeColumn( (ColumnSource) valueSource, table );
}
else {
return makeDerivedValue( (DerivedValueSource) valueSource, table );
}
}
private Column makeColumn(ColumnSource columnSource, TableSpecification table) {
String name = columnSource.getName();
name = metadata.getOptions().getNamingStrategy().columnName( name );
name = quoteIdentifier( name );
final Column column = table.locateOrCreateColumn( name );
column.setNullable( columnSource.isNullable() );
column.setDefaultValue( columnSource.getDefaultValue() );
column.setSqlType( columnSource.getSqlType() );
column.setSize( columnSource.getSize() );
column.setDatatype( 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 DerivedValue makeDerivedValue(DerivedValueSource derivedValueSource, TableSpecification table) {
return table.locateOrCreateDerivedValue( derivedValueSource.getExpression() );
}
private void processFetchProfiles(EntitySource entitySource, EntityBinding entityBinding) {
}
private static class AttributeJavaTypeDeterminerDelegate implements BeanInfoHelper.BeanInfoDelegate {
private final String attributeName;
private Class<?> javaType = null;
private AttributeJavaTypeDeterminerDelegate(String attributeName) {
this.attributeName = attributeName;
}
@Override
public void processBeanInfo(BeanInfo beanInfo) throws Exception {
for ( PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors() ) {
if ( propertyDescriptor.getName().equals( attributeName ) ) {
javaType = propertyDescriptor.getPropertyType();
break;
}
}
}
}
}