From 13b00f89075bdeae81c8767d2f629599bfbb85f6 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 27 Jan 2022 11:47:14 +0100 Subject: [PATCH] massive cleanup of AnnotationBinder --- .../InFlightMetadataCollectorImpl.java | 3 +- .../model/IdGeneratorStrategyInterpreter.java | 2 +- .../org/hibernate/boot/model/TruthValue.java | 16 +- ...AnnotationMetadataSourceProcessorImpl.java | 22 +- .../hbm/HbmMetadataSourceProcessorImpl.java | 4 +- .../source/internal/hbm/ModelBinder.java | 118 +- .../org/hibernate/cfg/AnnotatedClassType.java | 8 +- .../org/hibernate/cfg/AnnotatedColumn.java | 2 +- .../cfg/AnnotatedDiscriminatorColumn.java | 2 +- .../hibernate/cfg/AnnotatedJoinColumn.java | 2 +- .../org/hibernate/cfg/AnnotationBinder.java | 1080 +++++++++-------- .../java/org/hibernate/cfg/BinderHelper.java | 22 +- .../org/hibernate/cfg/ColumnsBuilder.java | 13 +- .../hibernate/cfg/CreateKeySecondPass.java | 2 +- .../org/hibernate/cfg/InheritanceState.java | 12 +- .../cfg/annotations/CollectionBinder.java | 28 +- .../cfg/annotations/EntityBinder.java | 99 +- .../hibernate/cfg/annotations/MapBinder.java | 2 +- .../org/hibernate/mapping/ForeignKey.java | 4 +- .../java/org/hibernate/mapping/ManyToOne.java | 2 +- .../java/org/hibernate/mapping/OneToOne.java | 2 +- .../java/org/hibernate/mapping/RootClass.java | 2 +- .../org/hibernate/mapping/SimpleValue.java | 18 +- .../internal/StandardAnyTypeDefinition.java | 2 +- .../hibernate/query/CommonQueryContract.java | 2 +- 25 files changed, 693 insertions(+), 776 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index 11012af669..12f99cab7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -1177,7 +1176,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector type = AnnotatedClassType.EMBEDDABLE; } else if ( clazz.isAnnotationPresent( jakarta.persistence.MappedSuperclass.class ) ) { - type = AnnotatedClassType.EMBEDDABLE_SUPERCLASS; + type = AnnotatedClassType.MAPPED_SUPERCLASS; } else { type = AnnotatedClassType.NONE; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/IdGeneratorStrategyInterpreter.java b/hibernate-core/src/main/java/org/hibernate/boot/model/IdGeneratorStrategyInterpreter.java index 0b9f42cc31..cd16fc7b93 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/IdGeneratorStrategyInterpreter.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/IdGeneratorStrategyInterpreter.java @@ -24,7 +24,7 @@ public interface IdGeneratorStrategyInterpreter { * The Java type of the attribute defining the id whose value is to * be generated. */ - Class getIdType(); + Class getIdType(); /** * The {@link GeneratedValue#generator()} name. diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/TruthValue.java b/hibernate-core/src/main/java/org/hibernate/boot/model/TruthValue.java index 5e7ea4e394..28537d64c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/TruthValue.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/TruthValue.java @@ -19,16 +19,14 @@ public enum TruthValue { FALSE, UNKNOWN; - @SuppressWarnings("SimplifiableIfStatement") public boolean toBoolean(boolean defaultValue) { - if ( this == TRUE ) { - return true; - } - else if ( this == FALSE ) { - return false; - } - else { - return defaultValue; + switch (this) { + case TRUE: + return true; + case FALSE: + return false; + default: + return defaultValue; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index 99f1479671..f36350e28d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -79,8 +79,8 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc if ( metadataBuildingOptions.isXmlMappingEnabled() ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Ewww. This is temporary until we migrate to Jandex + StAX for annotation binding - final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) - .getMetadataProvider(); + final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) + ( (MetadataProviderInjector) reflectionManager ).getMetadataProvider(); for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { Object root = xmlBinding.getRoot(); if ( !(root instanceof JaxbEntityMappings) ) { @@ -98,21 +98,21 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc } for ( String className : managedResources.getAnnotatedClassNames() ) { - final Class annotatedClass = classLoaderService.classForName( className ); - categorizeAnnotatedClass( annotatedClass, attributeConverterManager, classLoaderService ); + final Class annotatedClass = classLoaderService.classForName( className ); + categorizeAnnotatedClass( annotatedClass, attributeConverterManager ); } - for ( Class annotatedClass : managedResources.getAnnotatedClassReferences() ) { - categorizeAnnotatedClass( annotatedClass, attributeConverterManager, classLoaderService ); + for ( Class annotatedClass : managedResources.getAnnotatedClassReferences() ) { + categorizeAnnotatedClass( annotatedClass, attributeConverterManager ); } } - private void categorizeAnnotatedClass(Class annotatedClass, AttributeConverterManager attributeConverterManager, ClassLoaderService cls) { + private void categorizeAnnotatedClass(Class annotatedClass, AttributeConverterManager attributeConverterManager) { final XClass xClass = reflectionManager.toXClass( annotatedClass ); // categorize it, based on assumption it does not fall into multiple categories if ( xClass.isAnnotationPresent( Converter.class ) ) { - //noinspection unchecked - attributeConverterManager.addAttributeConverter( annotatedClass ); + //noinspection unchecked, rawtypes + attributeConverterManager.addAttributeConverter( (Class) annotatedClass ); } else if ( xClass.isAnnotationPresent( Entity.class ) || xClass.isAnnotationPresent( MappedSuperclass.class ) ) { @@ -126,7 +126,6 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc } } - @SuppressWarnings("deprecation") private XClass toXClass(String className, ReflectionManager reflectionManager, ClassLoaderService cls) { return reflectionManager.toXClass( cls.classForName( className ) ); } @@ -136,7 +135,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc // use any persistence-unit-defaults defined in orm.xml ( (JpaOrmXmlPersistenceUnitDefaultAware) rootMetadataBuildingContext.getBuildingOptions() ).apply( new JpaOrmXmlPersistenceUnitDefaults() { - final Map persistenceUnitDefaults = reflectionManager.getDefaults(); + final Map persistenceUnitDefaults = reflectionManager.getDefaults(); @Override public String getDefaultSchemaName() { @@ -319,6 +318,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc rootMetadataBuildingContext.getMetadataCollector().addAttributeConverter( descriptor ); } + @SuppressWarnings("rawtypes") public void addAttributeConverter(Class converterClass) { rootMetadataBuildingContext.getMetadataCollector().addAttributeConverter( converterClass ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/HbmMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/HbmMetadataSourceProcessorImpl.java index fa4d84aef1..2bea3a1184 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/HbmMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/HbmMetadataSourceProcessorImpl.java @@ -150,9 +150,7 @@ public class HbmMetadataSourceProcessorImpl implements MetadataSourceProcessor { } @Override - public void postProcessEntityHierarchies() { - modelBinder.finishUp( rootBuildingContext ); - } + public void postProcessEntityHierarchies() {} @Override public void processResultSetMappings() { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index 851e609b33..626d70e0e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -150,7 +150,6 @@ import org.hibernate.tuple.GeneratedValueGeneration; import org.hibernate.tuple.GenerationTiming; import org.hibernate.type.AbstractSingleColumnStandardBasicType; import org.hibernate.type.BasicType; -import org.hibernate.type.ComponentType; import org.hibernate.type.CustomType; import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.StandardBasicTypes; @@ -192,9 +191,6 @@ public class ModelBinder { this.relationalObjectBinder = new RelationalObjectBinder( context ); } - public void finishUp(MetadataBuildingContext context) { - } - public void bindEntityHierarchy(EntityHierarchySourceImpl hierarchySource) { final RootClass rootEntityDescriptor = new RootClass( hierarchySource.getRootEntityMappingDocument() ); bindRootEntity( hierarchySource, rootEntityDescriptor ); @@ -308,7 +304,7 @@ public class ModelBinder { // Configuration applied a similar logic but that capability is no longer // accessible from Configuration switch ( mappingDocument.getBuildingOptions().getSharedCacheMode() ) { - case ALL: { + case ALL: caching = new Caching( null, mappingDocument.getBuildingOptions().getImplicitCacheAccessType(), @@ -316,24 +312,11 @@ public class ModelBinder { TruthValue.UNKNOWN ); break; - } - case NONE: { - // Ideally we'd disable all caching... - break; - } - case ENABLE_SELECTIVE: { - // this is default behavior for hbm.xml - break; - } - case DISABLE_SELECTIVE: { - // really makes no sense for hbm.xml - break; - } - default: { - // null or UNSPECIFIED, nothing to do. IMO for hbm.xml this is equivalent - // to ENABLE_SELECTIVE - break; - } + case NONE: // Ideally we'd disable all caching... + case ENABLE_SELECTIVE: // this is default behavior for hbm.xml + case DISABLE_SELECTIVE: // really makes no sense for hbm.xml + default: // null or UNSPECIFIED, nothing to do. IMO for hbm.xml this is equivalent to ENABLE_SELECTIVE + // do nothing } } @@ -464,7 +447,7 @@ public class ModelBinder { } } - bindCustomSql( sourceDocument, entitySource, entityDescriptor ); + bindCustomSql( entitySource, entityDescriptor ); final JdbcEnvironment jdbcEnvironment = sourceDocument.getMetadataCollector().getDatabase().getJdbcEnvironment(); @@ -846,8 +829,7 @@ public class ModelBinder { idPropertyName, idPropertyName == null, idClassName == null && idPropertyName == null, - identifierSource.getEmbeddableSource().isDynamic(), - identifierSource.getIdentifierAttributeSource().getXmlNodeName() + identifierSource.getEmbeddableSource().isDynamic() ); finishBindingCompositeIdentifier( @@ -892,8 +874,7 @@ public class ModelBinder { null, true, idClassName == null, - false, - null + false ); if ( idClassName != null ) { @@ -911,8 +892,7 @@ public class ModelBinder { null, true, true, - false, - null + false ); rootEntityDescriptor.setIdentifierMapper( mapper ); @@ -1758,11 +1738,7 @@ public class ModelBinder { secondaryTableJoin.setTable( secondaryTable ); entityTableXref.addSecondaryTable( mappingDocument, logicalTableName, secondaryTableJoin ); - bindCustomSql( - mappingDocument, - secondaryTableSource, - secondaryTableJoin - ); + bindCustomSql( secondaryTableSource, secondaryTableJoin ); secondaryTableJoin.setSequentialSelect( secondaryTableSource.getFetchStyle() == FetchStyle.SELECT ); secondaryTableJoin.setInverse( secondaryTableSource.isInverse() ); @@ -1841,7 +1817,6 @@ public class ModelBinder { componentBinding, containingClassName, attributeName, - embeddedSource.getXmlNodeName(), embeddedSource.isVirtualAttribute() ); @@ -2006,7 +1981,6 @@ public class ModelBinder { sourceDocument, oneToOneBinding.getReferencedEntityName(), propertyRef, - true, "" ); } @@ -2030,7 +2004,6 @@ public class ModelBinder { MappingDocument mappingDocument, String referencedEntityName, String referencedPropertyName, - boolean isUnique, String sourceElementSynopsis) { PersistentClass entityBinding = mappingDocument.getMetadataCollector().getEntityBinding( referencedEntityName ); if ( entityBinding == null ) { @@ -2039,7 +2012,7 @@ public class ModelBinder { new DelayedPropertyReferenceHandlerImpl( referencedEntityName, referencedPropertyName, - isUnique, + true, sourceElementSynopsis, mappingDocument.getOrigin() ), @@ -2054,7 +2027,7 @@ public class ModelBinder { new DelayedPropertyReferenceHandlerImpl( referencedEntityName, referencedPropertyName, - isUnique, + true, sourceElementSynopsis, mappingDocument.getOrigin() ), @@ -2068,9 +2041,7 @@ public class ModelBinder { referencedPropertyName, sourceElementSynopsis ); - if ( isUnique ) { - ( (SimpleValue) propertyBinding.getValue() ).setAlternateUniqueKey( true ); - } + ( (SimpleValue) propertyBinding.getValue() ).setAlternateUniqueKey( true ); } } } @@ -2191,7 +2162,6 @@ public class ModelBinder { sourceDocument, manyToOneBinding.getReferencedEntityName(), propertyRef, - true, "" ); } @@ -2309,7 +2279,7 @@ public class ModelBinder { String entityName) { final String attributeName = anyMapping.getName(); - bindAny( sourceDocument, anyMapping, anyBinding, anyMapping.getAttributeRole(), anyMapping.getAttributePath() ); + bindAny( sourceDocument, anyMapping, anyBinding, anyMapping.getAttributeRole() ); prepareValueTypeViaReflection( sourceDocument, anyBinding, entityName, attributeName, anyMapping.getAttributeRole() ); @@ -2330,8 +2300,7 @@ public class ModelBinder { MappingDocument sourceDocument, final AnyMappingSource anyMapping, Any anyBinding, - final AttributeRole attributeRole, - AttributePath attributePath) { + final AttributeRole attributeRole) { anyBinding.setLazy( anyMapping.isLazy() ); @@ -2592,19 +2561,7 @@ public class ModelBinder { property.setMetaAttributes( propertySource.getToolingHintContext().getMetaAttributeMap() ); if ( log.isDebugEnabled() ) { - final StringBuilder message = new StringBuilder() - .append( "Mapped property: " ) - .append( propertySource.getName() ) - .append( " -> [" ); - final Iterator itr = property.getValue().getColumnIterator(); - while ( itr.hasNext() ) { - message.append( itr.next().getText() ); - if ( itr.hasNext() ) { - message.append( ", " ); - } - } - message.append( "]" ); - log.debug( message.toString() ); + log.debug( "Mapped property: " + propertySource.getName() + " -> [" + columns( property.getValue() ) + "]" ); } } @@ -2614,7 +2571,6 @@ public class ModelBinder { Component component, String containingClassName, String propertyName, - String xmlNodeName, boolean isVirtual) { final String fullRole = embeddableSource.getAttributeRoleBase().getFullPath(); final String explicitComponentClassName = extractExplicitComponentClassName( embeddableSource ); @@ -2629,8 +2585,7 @@ public class ModelBinder { propertyName, isVirtual, isVirtual, - embeddableSource.isDynamic(), - xmlNodeName + embeddableSource.isDynamic() ); } @@ -2652,8 +2607,7 @@ public class ModelBinder { String propertyName, boolean isComponentEmbedded, boolean isVirtual, - boolean isDynamic, - String xmlNodeName) { + boolean isDynamic) { componentBinding.setMetaAttributes( embeddableSource.getToolingHintContext().getMetaAttributeMap() ); @@ -3014,7 +2968,6 @@ public class ModelBinder { } private static void bindCustomSql( - MappingDocument sourceDocument, EntitySource entitySource, PersistentClass entityDescriptor) { if ( entitySource.getCustomSqlInsert() != null ) { @@ -3045,7 +2998,6 @@ public class ModelBinder { } private static void bindCustomSql( - MappingDocument sourceDocument, SecondaryTableSource secondaryTableSource, Join secondaryTable) { if ( secondaryTableSource.getCustomSqlInsert() != null ) { @@ -3196,18 +3148,6 @@ public class ModelBinder { } } - private String columns(Value value) { - final StringBuilder builder = new StringBuilder(); - final Iterator selectableItr = value.getColumnIterator(); - while ( selectableItr.hasNext() ) { - builder.append( selectableItr.next().getText() ); - if ( selectableItr.hasNext() ) { - builder.append( ", " ); - } - } - return builder.toString(); - } - private void bindCollectionTable() { // 2 main branches here: // 1) one-to-many @@ -3485,7 +3425,6 @@ public class ModelBinder { elementBinding, null, embeddableSource.getAttributePathBase().getProperty(), - getPluralAttributeSource().getXmlNodeName(), false ); @@ -3668,9 +3607,7 @@ public class ModelBinder { mappingDocument, elementSource, elementBinding, - getPluralAttributeSource().getAttributeRole().append( "element" ), - getPluralAttributeSource().getAttributePath().append( "element" ) - + getPluralAttributeSource().getAttributeRole().append( "element" ) ); getCollectionBinding().setElement( elementBinding ); // Collection#setWhere is used to set the "where" clause that applies to the collection table @@ -4003,7 +3940,6 @@ public class ModelBinder { componentBinding, null, pluralAttributeSource.getName(), - mapKeySource.getXmlNodeName(), false ); collectionBinding.setIndex( componentBinding ); @@ -4050,8 +3986,7 @@ public class ModelBinder { mappingDocument, mapKeySource, mapKeyBinding, - pluralAttributeSource.getAttributeRole().append( "key" ), - pluralAttributeSource.getAttributePath().append( "key" ) + pluralAttributeSource.getAttributeRole().append( "key" ) ); collectionBinding.setIndex( mapKeyBinding ); } @@ -4287,6 +4222,17 @@ public class ModelBinder { entityBinding.getTable().addUniqueKey( uk ); } + } + private String columns(Value value) { + final StringBuilder builder = new StringBuilder(); + final Iterator selectableItr = value.getColumnIterator(); + while ( selectableItr.hasNext() ) { + builder.append( selectableItr.next().getText() ); + if ( selectableItr.hasNext() ) { + builder.append( ", " ); + } + } + return builder.toString(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedClassType.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedClassType.java index b872573fc4..11a41776ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedClassType.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedClassType.java @@ -18,15 +18,15 @@ public enum AnnotatedClassType { */ NONE, /** - * has @Entity annotation + * has an {@link jakarta.persistence.Entity} annotation */ ENTITY, /** - * has an @Embeddable annotation + * has an {@link jakarta.persistence.Embeddable} annotation */ EMBEDDABLE, /** - * has @EmbeddedSuperclass annotation + * has {@link jakarta.persistence.MappedSuperclass} annotation */ - EMBEDDABLE_SUPERCLASS + MAPPED_SUPERCLASS } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java index 4dcce1956c..3254fb7c95 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java @@ -867,7 +867,7 @@ public class AnnotatedColumn { @Override public String toString() { return String.format( - "Ejb3Column{table=%s, mappingColumn=%s, insertable=%s, updatable=%s, unique=%s}", + "Column{table=%s, mappingColumn=%s, insertable=%s, updatable=%s, unique=%s}", getTable(), mappingColumn.getName(), insertable, updatable, unique ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedDiscriminatorColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedDiscriminatorColumn.java index fbd91485bb..2dd125723a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedDiscriminatorColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedDiscriminatorColumn.java @@ -85,7 +85,7 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { @Override public String toString() { - return String.format("Ejb3DiscriminatorColumn{logicalColumnName'%s', discriminatorTypeName='%s'}", + return String.format("DiscriminatorColumn{logicalColumnName'%s', discriminatorTypeName='%s'}", getLogicalColumnName(), discriminatorTypeName ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java index defe7b73d2..c7c3f7a06a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java @@ -968,7 +968,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { @Override public String toString() { return String.format( - "Ejb3JoinColumn{logicalColumnName='%s', referencedColumn='%s', mappedBy='%s'}", + "JoinColumn{logicalColumnName='%s', referencedColumn='%s', mappedBy='%s'}", getLogicalColumnName(), referencedColumn, mappedBy ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 3f15239f40..5999ffc7de 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -99,7 +99,6 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.InFlightMetadataCollector.EntityTableXref; import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.cfg.annotations.BasicValueBinder; import org.hibernate.cfg.annotations.CollectionBinder; import org.hibernate.cfg.annotations.EntityBinder; import org.hibernate.cfg.annotations.HCANNHelper; @@ -133,7 +132,6 @@ import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.RootClass; -import org.hibernate.mapping.Selectable; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SingleTableSubclass; import org.hibernate.mapping.Subclass; @@ -196,7 +194,6 @@ import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.PrimaryKeyJoinColumns; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.SequenceGenerators; -import jakarta.persistence.SharedCacheMode; import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.SqlResultSetMappings; import jakarta.persistence.Table; @@ -205,7 +202,12 @@ import jakarta.persistence.TableGenerators; import jakarta.persistence.UniqueConstraint; import jakarta.persistence.Version; +import static org.hibernate.cfg.AnnotatedColumn.buildColumnFromAnnotation; +import static org.hibernate.cfg.AnnotatedJoinColumn.buildJoinColumnsWithDefaultColumnSuffix; +import static org.hibernate.cfg.BinderHelper.getMappedSuperclassOrNull; +import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder; import static org.hibernate.internal.CoreLogging.messageLogger; +import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; /** * JSR 175 annotation binder which reads the annotations from classes, applies the @@ -227,15 +229,16 @@ import static org.hibernate.internal.CoreLogging.messageLogger; * @author Emmanuel Bernard * @author Hardy Ferentschik */ -@SuppressWarnings("unchecked") +@SuppressWarnings("deprecation") public final class AnnotationBinder { private static final CoreMessageLogger LOG = messageLogger( AnnotationBinder.class ); private AnnotationBinder() { } + @SuppressWarnings("unchecked") public static void bindDefaults(MetadataBuildingContext context) { - Map defaults = context.getBootstrapContext().getReflectionManager().getDefaults(); + Map defaults = context.getBootstrapContext().getReflectionManager().getDefaults(); // id generators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -478,7 +481,10 @@ public final class AnnotationBinder { ); } - private static void bindNamedStoredProcedureQueries(NamedStoredProcedureQueries annotation, MetadataBuildingContext context, boolean isDefault) { + private static void bindNamedStoredProcedureQueries( + NamedStoredProcedureQueries annotation, + MetadataBuildingContext context, + boolean isDefault) { if ( annotation != null ) { for ( NamedStoredProcedureQuery queryAnnotation : annotation.value() ) { bindNamedStoredProcedureQuery( queryAnnotation, context, isDefault ); @@ -486,7 +492,10 @@ public final class AnnotationBinder { } } - private static void bindNamedStoredProcedureQuery(NamedStoredProcedureQuery annotation, MetadataBuildingContext context, boolean isDefault) { + private static void bindNamedStoredProcedureQuery( + NamedStoredProcedureQuery annotation, + MetadataBuildingContext context, + boolean isDefault) { if ( annotation != null ) { QueryBinder.bindNamedStoredProcedureQuery( annotation, context, isDefault ); } @@ -550,6 +559,172 @@ public final class AnnotationBinder { XClass clazzToProcess, Map inheritanceStatePerClass, MetadataBuildingContext context) throws MappingException { + + detectMappedSuperclassProblems( clazzToProcess ); + + switch ( context.getMetadataCollector().getClassType( clazzToProcess ) ) { + case MAPPED_SUPERCLASS: + // Allow queries and filters to be declared by a @MappedSuperclass + bindQueries( clazzToProcess, context ); + bindFilterDefs( clazzToProcess, context ); + //fall through: + case EMBEDDABLE: + case NONE: + return; + } + + if ( LOG.isDebugEnabled() ) { + LOG.debugf( "Binding entity from annotated class: %s", clazzToProcess.getName() ); + } + + //TODO: be more strict with secondary table allowance (not for ids, not for secondary table join columns etc) + InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess ); + PersistentClass superEntity = getSuperEntity( + clazzToProcess, + inheritanceStatePerClass, + context, + inheritanceState + ); + detectedAttributeOverrideProblem( clazzToProcess, superEntity ); + + PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity, context ); + EntityBinder entityBinder = new EntityBinder( clazzToProcess, persistentClass, context ); + + bindQueries( clazzToProcess, context ); + bindFilterDefs( clazzToProcess, context ); + + final AnnotatedJoinColumn[] inheritanceJoinedColumns = + makeInheritanceJoinColumns( clazzToProcess, context, inheritanceState, superEntity ); + final AnnotatedDiscriminatorColumn discriminatorColumn = + handleDiscriminatorColumn( clazzToProcess, context, inheritanceState, entityBinder ); + + entityBinder.setProxy( clazzToProcess.getAnnotation( Proxy.class ) ); + entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) ); + entityBinder.setWhere( getOverridableAnnotation( clazzToProcess, Where.class, context ) ); + entityBinder.applyCaching( clazzToProcess, context.getBuildingOptions().getSharedCacheMode(), context ); + + bindFiltersAndFilterDefs( clazzToProcess, entityBinder, context ); + + entityBinder.bindEntity(); + + Table table = handleClassTable( + clazzToProcess, + context, + inheritanceState, + superEntity, + entityBinder + ); + + PropertyHolder propertyHolder = buildPropertyHolder( + clazzToProcess, + persistentClass, + entityBinder, + context, + inheritanceStatePerClass + ); + + handleSecondaryTables( clazzToProcess, entityBinder ); + + handleInheritance( + clazzToProcess, + context, + inheritanceState, + persistentClass, + entityBinder, + inheritanceJoinedColumns, + discriminatorColumn, + propertyHolder + ); + + // try to find class level generators + HashMap classGenerators = buildGenerators( clazzToProcess, context ); + handleTypeDescriptorRegistrations( clazzToProcess, context ); + bindEmbeddableInstantiatorRegistrations( clazzToProcess, context ); + + // check properties + final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess(); + inheritanceState.postProcess( persistentClass, entityBinder ); + + Set idPropertiesIfIdClass = handleIdClass( + persistentClass, + inheritanceState, + context, + entityBinder, + propertyHolder, + elementsToProcess, + inheritanceStatePerClass + ); + + processIdPropertiesIfNotAlready( + persistentClass, + inheritanceState, + context, + entityBinder, + propertyHolder, + classGenerators, + idPropertiesIfIdClass, + elementsToProcess, + inheritanceStatePerClass + ); + + if ( persistentClass instanceof RootClass ) { + context.getMetadataCollector().addSecondPass( new CreateKeySecondPass( (RootClass) persistentClass ) ); + } + + if ( persistentClass instanceof Subclass ) { + assert superEntity != null; + superEntity.addSubclass( (Subclass) persistentClass ); + } + + context.getMetadataCollector().addEntityBinding( persistentClass ); + + //Process secondary tables and complementary definitions (ie o.h.a.Table) + context.getMetadataCollector() + .addSecondPass( new SecondaryTableSecondPass( entityBinder, propertyHolder, clazzToProcess ) ); + + processComplementaryTableDefinitions( clazzToProcess, entityBinder, table ); + + bindCallbacks( clazzToProcess, persistentClass, context ); + } + + private static void detectedAttributeOverrideProblem(XClass clazzToProcess, PersistentClass superEntity) { + if ( superEntity != null && ( + clazzToProcess.isAnnotationPresent( AttributeOverride.class ) || + clazzToProcess.isAnnotationPresent( AttributeOverrides.class ) ) ) { + LOG.unsupportedAttributeOverrideWithEntityInheritance( clazzToProcess.getName() ); + } + } + + private static Set handleIdClass( + PersistentClass persistentClass, + InheritanceState inheritanceState, + MetadataBuildingContext context, + EntityBinder entityBinder, + PropertyHolder propertyHolder, + InheritanceState.ElementsToProcess elementsToProcess, + Map inheritanceStatePerClass) { + + Set idPropertiesIfIdClass = new HashSet<>(); + + boolean isIdClass = mapAsIdClass( + inheritanceStatePerClass, + inheritanceState, + persistentClass, + entityBinder, + propertyHolder, + elementsToProcess, + idPropertiesIfIdClass, + context + ); + + if ( !isIdClass ) { + entityBinder.setWrapIdsInEmbeddedComponents( elementsToProcess.getIdPropertyCount() > 1 ); + } + + return idPropertiesIfIdClass; + } + + private static void detectMappedSuperclassProblems(XClass clazzToProcess) { //@Entity and @MappedSuperclass on the same class leads to a NPE down the road if ( clazzToProcess.isAnnotationPresent( Entity.class ) && clazzToProcess.isAnnotationPresent( MappedSuperclass.class ) ) { @@ -561,101 +736,72 @@ public final class AnnotationBinder { && clazzToProcess.isAnnotationPresent( MappedSuperclass.class ) ) { LOG.unsupportedMappedSuperclassWithEntityInheritance( clazzToProcess.getName() ); } + } - //TODO: be more strict with secondary table allowance (not for ids, not for secondary table join columns etc) - InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess ); - AnnotatedClassType classType = context.getMetadataCollector().getClassType( clazzToProcess ); + private static AnnotatedDiscriminatorColumn handleDiscriminatorColumn( + XClass clazzToProcess, + MetadataBuildingContext context, + InheritanceState inheritanceState, + EntityBinder entityBinder) { - //Queries declared in MappedSuperclass should be usable in Subclasses - if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) { - bindQueries( clazzToProcess, context ); - bindFilterDefs( clazzToProcess, context ); + switch ( inheritanceState.getType() ) { + case SINGLE_TABLE: + return processSingleTableDiscriminatorProperties( + clazzToProcess, + context, + inheritanceState, + entityBinder + ); + case JOINED: + return processJoinedDiscriminatorProperties( + clazzToProcess, + context, + inheritanceState, + entityBinder + ); + default: + return null; } + } - if ( !isEntityClassType( clazzToProcess, classType ) ) { - return; - } - - if ( LOG.isDebugEnabled() ) { - LOG.debugf( "Binding entity from annotated class: %s", clazzToProcess.getName() ); - } - - PersistentClass superEntity = getSuperEntity( - clazzToProcess, - inheritanceStatePerClass, - context, - inheritanceState + private static void handleSecondaryTables(XClass clazzToProcess, EntityBinder entityBinder) { + jakarta.persistence.SecondaryTable secTabAnn = clazzToProcess.getAnnotation( + jakarta.persistence.SecondaryTable.class ); - - if(superEntity != null && ( - clazzToProcess.getAnnotation( AttributeOverride.class ) != null || - clazzToProcess.getAnnotation( AttributeOverrides.class ) != null ) ) { - LOG.unsupportedAttributeOverrideWithEntityInheritance( clazzToProcess.getName() ); - } - - PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity, context ); - Entity entityAnn = clazzToProcess.getAnnotation( Entity.class ); - EntityBinder entityBinder = new EntityBinder( - entityAnn, - clazzToProcess, - persistentClass, - context + jakarta.persistence.SecondaryTables secTabsAnn = clazzToProcess.getAnnotation( + jakarta.persistence.SecondaryTables.class ); - entityBinder.setInheritanceState( inheritanceState ); + entityBinder.firstLevelSecondaryTablesBinding( secTabAnn, secTabsAnn ); + } - bindQueries( clazzToProcess, context ); - bindFilterDefs( clazzToProcess, context ); + private static jakarta.persistence.Table handleClassTable( + XClass clazzToProcess, + MetadataBuildingContext context, + InheritanceState inheritanceState, + PersistentClass superEntity, + EntityBinder entityBinder) { - String schema = ""; - String table = ""; //might be no @Table annotation on the annotated class - String catalog = ""; List uniqueConstraints = new ArrayList<>(); - jakarta.persistence.Table tabAnn = null; - if ( clazzToProcess.isAnnotationPresent( jakarta.persistence.Table.class ) ) { - tabAnn = clazzToProcess.getAnnotation( jakarta.persistence.Table.class ); - table = tabAnn.name(); - schema = tabAnn.schema(); - catalog = tabAnn.catalog(); - uniqueConstraints = TableBinder.buildUniqueConstraintHolders( tabAnn.uniqueConstraints() ); - } - - AnnotatedJoinColumn[] inheritanceJoinedColumns = makeInheritanceJoinColumns( - clazzToProcess, - context, - inheritanceState, - superEntity - ); - - final AnnotatedDiscriminatorColumn discriminatorColumn; - if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) { - discriminatorColumn = processSingleTableDiscriminatorProperties( - clazzToProcess, - context, - inheritanceState, - entityBinder - ); - } - else if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) { - discriminatorColumn = processJoinedDiscriminatorProperties( - clazzToProcess, - context, - inheritanceState, - entityBinder - ); + jakarta.persistence.Table tableAnnotation; + String schema; + String table; + String catalog; + boolean hasTableAnnotation = clazzToProcess.isAnnotationPresent( Table.class ); + if ( hasTableAnnotation ) { + tableAnnotation = clazzToProcess.getAnnotation( jakarta.persistence.Table.class ); + table = tableAnnotation.name(); + schema = tableAnnotation.schema(); + catalog = tableAnnotation.catalog(); + uniqueConstraints = TableBinder.buildUniqueConstraintHolders( tableAnnotation.uniqueConstraints() ); } else { - discriminatorColumn = null; + //might be no @Table annotation on the annotated class + tableAnnotation = null; + schema = ""; + table = ""; + catalog = ""; } - entityBinder.setProxy( clazzToProcess.getAnnotation( Proxy.class ) ); - entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) ); - entityBinder.setWhere( getOverridableAnnotation( clazzToProcess, Where.class, context ) ); - applyCacheSettings( entityBinder, clazzToProcess, context ); - - bindFiltersAndFilterDefs( clazzToProcess, entityBinder, context ); - - entityBinder.bindEntity(); - if ( inheritanceState.hasTable() ) { Check checkAnn = getOverridableAnnotation( clazzToProcess, Check.class, context ); String constraints = checkAnn == null @@ -676,7 +822,7 @@ public final class AnnotationBinder { ); } else { - if ( clazzToProcess.isAnnotationPresent( Table.class ) ) { + if ( hasTableAnnotation ) { LOG.invalidTableAnnotation( clazzToProcess.getName() ); } @@ -688,78 +834,72 @@ public final class AnnotationBinder { } } + return tableAnnotation; + } - PropertyHolder propertyHolder = PropertyHolderBuilder.buildPropertyHolder( - clazzToProcess, - persistentClass, - entityBinder, - context, - inheritanceStatePerClass - ); + private static void processComplementaryTableDefinitions(XClass clazzToProcess, EntityBinder entityBinder, Table tabAnn) { + //add process complementary Table definition (index & all) + entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Table.class ) ); + entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Tables.class ) ); + entityBinder.processComplementaryTableDefinitions(tabAnn); + } - jakarta.persistence.SecondaryTable secTabAnn = clazzToProcess.getAnnotation( - jakarta.persistence.SecondaryTable.class - ); - jakarta.persistence.SecondaryTables secTabsAnn = clazzToProcess.getAnnotation( - jakarta.persistence.SecondaryTables.class - ); - entityBinder.firstLevelSecondaryTablesBinding( secTabAnn, secTabsAnn ); + private static void handleInheritance( + XClass clazzToProcess, + MetadataBuildingContext context, + InheritanceState inheritanceState, + PersistentClass persistentClass, + EntityBinder entityBinder, + AnnotatedJoinColumn[] inheritanceJoinedColumns, + AnnotatedDiscriminatorColumn discriminatorColumn, + PropertyHolder propertyHolder) { OnDelete onDeleteAnn = clazzToProcess.getAnnotation( OnDelete.class ); - boolean onDeleteAppropriate = false; // todo : sucks that this is separate from RootClass distinction final boolean isInheritanceRoot = !inheritanceState.hasParents(); final boolean hasSubclasses = inheritanceState.hasSiblings(); - if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) { - if ( inheritanceState.hasParents() ) { - onDeleteAppropriate = true; - final JoinedSubclass jsc = ( JoinedSubclass ) persistentClass; - DependantValue key = new DependantValue( context, jsc.getTable(), jsc.getIdentifier() ); - jsc.setKey( key ); - ForeignKey fk = clazzToProcess.getAnnotation( ForeignKey.class ); - if ( fk != null && !BinderHelper.isEmptyAnnotationValue( fk.name() ) ) { - key.setForeignKeyName( fk.name() ); - } - else { - final PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ); - final PrimaryKeyJoinColumns pkJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class ); - final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); - if ( pkJoinColumns != null && ( pkJoinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT - || pkJoinColumns.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) { - // don't apply a constraint based on ConstraintMode - key.setForeignKeyName( "none" ); - } - else if ( pkJoinColumns != null && !StringHelper.isEmpty( pkJoinColumns.foreignKey().name() ) ) { - key.setForeignKeyName( pkJoinColumns.foreignKey().name() ); - } - else if ( pkJoinColumn != null && ( pkJoinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT - || pkJoinColumn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault )) { - // don't apply a constraint based on ConstraintMode - key.setForeignKeyName( "none" ); - } - else if ( pkJoinColumn != null && !StringHelper.isEmpty( pkJoinColumn.foreignKey().name() ) ) { - key.setForeignKeyName( pkJoinColumn.foreignKey().name() ); - } - } - if ( onDeleteAnn != null ) { - key.setCascadeDeleteEnabled( OnDeleteAction.CASCADE.equals( onDeleteAnn.action() ) ); - } - else { - key.setCascadeDeleteEnabled( false ); - } - //we are never in a second pass at that stage, so queue it - context.getMetadataCollector().addSecondPass( new JoinedSubclassFkSecondPass( jsc, inheritanceJoinedColumns, key, context ) ); - context.getMetadataCollector().addSecondPass( new CreateKeySecondPass( jsc ) ); - } + boolean onDeleteAppropriate = false; - if ( isInheritanceRoot ) { - // the class we are processing is the root of the hierarchy, see if we had a discriminator column - // (it is perfectly valid for joined subclasses to not have discriminators). - if ( discriminatorColumn != null ) { - // we have a discriminator column - if ( hasSubclasses || !discriminatorColumn.isImplicit() ) { + switch ( inheritanceState.getType() ) { + case JOINED: + if ( inheritanceState.hasParents() ) { + onDeleteAppropriate = true; + JoinedSubclass jsc = (JoinedSubclass) persistentClass; + DependantValue key = new DependantValue( context, jsc.getTable(), jsc.getIdentifier() ); + jsc.setKey( key ); + handleForeignKeys( clazzToProcess, context, key ); + key.setCascadeDeleteEnabled( onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action() ); + //we are never in a second pass at that stage, so queue it + context.getMetadataCollector() + .addSecondPass( new JoinedSubclassFkSecondPass( jsc, inheritanceJoinedColumns, key, context) ); + context.getMetadataCollector() + .addSecondPass( new CreateKeySecondPass( jsc ) ); + } + + if ( isInheritanceRoot ) { + // the class we are processing is the root of the hierarchy, see if we had a discriminator column + // (it is perfectly valid for joined subclasses to not have discriminators). + if ( discriminatorColumn != null ) { + // we have a discriminator column + if ( hasSubclasses || !discriminatorColumn.isImplicit() ) { + bindDiscriminatorColumnToRootPersistentClass( + (RootClass) persistentClass, + discriminatorColumn, + entityBinder.getSecondaryTables(), + propertyHolder, + context + ); + //bind it again since the type might have changed + entityBinder.bindDiscriminatorValue(); + } + } + } + break; + case SINGLE_TABLE: + if ( isInheritanceRoot ) { + if ( hasSubclasses || discriminatorColumn != null && !discriminatorColumn.isImplicit() ) { bindDiscriminatorColumnToRootPersistentClass( (RootClass) persistentClass, discriminatorColumn, @@ -771,92 +911,46 @@ public final class AnnotationBinder { entityBinder.bindDiscriminatorValue(); } } - } - } - else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) { - if ( isInheritanceRoot ) { - if ( hasSubclasses || !discriminatorColumn.isImplicit() ) { - bindDiscriminatorColumnToRootPersistentClass( - (RootClass) persistentClass, - discriminatorColumn, - entityBinder.getSecondaryTables(), - propertyHolder, - context - ); - //bind it again since the type might have changed - entityBinder.bindDiscriminatorValue(); - } - } + break; } if ( onDeleteAnn != null && !onDeleteAppropriate ) { - LOG.invalidOnDeleteAnnotation(propertyHolder.getEntityName()); + LOG.invalidOnDeleteAnnotation( propertyHolder.getEntityName() ); } + } - // try to find class level generators - HashMap classGenerators = buildGenerators( clazzToProcess, context ); - handleTypeDescriptorRegistrations( clazzToProcess, context ); - bindEmbeddableInstantiatorRegistrations( clazzToProcess, context ); - - // check properties - final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess(); - inheritanceState.postProcess( persistentClass, entityBinder ); - - final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE - && inheritanceState.hasParents(); - Set idPropertiesIfIdClass = new HashSet<>(); - boolean isIdClass = mapAsIdClass( - inheritanceStatePerClass, - inheritanceState, - persistentClass, - entityBinder, - propertyHolder, - elementsToProcess, - idPropertiesIfIdClass, - context - ); - - if ( !isIdClass ) { - entityBinder.setWrapIdsInEmbeddedComponents( elementsToProcess.getIdPropertyCount() > 1 ); - } - - processIdPropertiesIfNotAlready( - inheritanceStatePerClass, - context, - persistentClass, - entityBinder, - propertyHolder, - classGenerators, - elementsToProcess, - subclassAndSingleTableStrategy, - idPropertiesIfIdClass - ); - - if ( !inheritanceState.hasParents() ) { - final RootClass rootClass = ( RootClass ) persistentClass; - context.getMetadataCollector().addSecondPass( new CreateKeySecondPass( rootClass ) ); + private static void handleForeignKeys(XClass clazzToProcess, MetadataBuildingContext context, DependantValue key) { + ForeignKey foreignKey = clazzToProcess.getAnnotation( ForeignKey.class ); + if ( foreignKey != null && !BinderHelper.isEmptyAnnotationValue( foreignKey.name() ) ) { + key.setForeignKeyName( foreignKey.name() ); } else { - superEntity.addSubclass( ( Subclass ) persistentClass ); + PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ); + PrimaryKeyJoinColumns pkJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class ); + final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); + if ( pkJoinColumns != null && ( pkJoinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT + || pkJoinColumns.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) { + // don't apply a constraint based on ConstraintMode + key.disableForeignKey(); + } + else if ( pkJoinColumns != null && !StringHelper.isEmpty( pkJoinColumns.foreignKey().name() ) ) { + key.setForeignKeyName( pkJoinColumns.foreignKey().name() ); + if ( !BinderHelper.isEmptyAnnotationValue( pkJoinColumns.foreignKey().foreignKeyDefinition() ) ) { + key.setForeignKeyDefinition( pkJoinColumns.foreignKey().foreignKeyDefinition() ); + } + } + else if ( pkJoinColumn != null && ( pkJoinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT + || pkJoinColumn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) { + // don't apply a constraint based on ConstraintMode + key.disableForeignKey(); + } + else if ( pkJoinColumn != null && !StringHelper.isEmpty( pkJoinColumn.foreignKey().name() ) ) { + key.setForeignKeyName( pkJoinColumn.foreignKey().name() ); + if ( !BinderHelper.isEmptyAnnotationValue( pkJoinColumn.foreignKey().foreignKeyDefinition() ) ) { + key.setForeignKeyDefinition( pkJoinColumn.foreignKey().foreignKeyDefinition() ); + } + } } - - context.getMetadataCollector().addEntityBinding( persistentClass ); - - //Process secondary tables and complementary definitions (ie o.h.a.Table) - context.getMetadataCollector().addSecondPass( - new SecondaryTableSecondPass( - entityBinder, - propertyHolder, - clazzToProcess - ) - ); - - //add process complementary Table definition (index & all) - entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Table.class ) ); - entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Tables.class ) ); - entityBinder.processComplementaryTableDefinitions( tabAnn ); - - bindCallbacks( clazzToProcess, persistentClass, context ); } public static T getOverridableAnnotation( @@ -889,6 +983,7 @@ public final class AnnotationBinder { if ( overridesAnnotation != null && overridesAnnotation.value().equals(annotationType) ) { try { + //noinspection unchecked Class overrideDialect = (Class) type.getDeclaredMethod("dialect").invoke(annotation); if ( overrideDialect.isAssignableFrom( dialect.getClass() ) ) { @@ -898,6 +993,7 @@ public final class AnnotationBinder { type.getDeclaredMethod("sameOrAfter").invoke(annotation); if ( dialect.getVersion().isBefore( before.major(), before.minor() ) && dialect.getVersion().isSameOrAfter( sameOrAfter.major(), sameOrAfter.minor() ) ) { + //noinspection unchecked return (T) type.getDeclaredMethod("override").invoke(annotation); } } @@ -923,8 +1019,8 @@ public final class AnnotationBinder { final JavaTypeRegistrations annotation = annotatedElement.getAnnotation( JavaTypeRegistrations.class ); if ( annotation != null ) { final JavaTypeRegistration[] registrations = annotation.value(); - for ( int i = 0; i < registrations.length; i++ ) { - handleJavaTypeRegistration( context, managedBeanRegistry, registrations[i] ); + for (JavaTypeRegistration registration : registrations) { + handleJavaTypeRegistration( context, managedBeanRegistry, registration ); } } } @@ -937,8 +1033,8 @@ public final class AnnotationBinder { final JdbcTypeRegistrations jdbcTypesAnn = annotatedElement.getAnnotation( JdbcTypeRegistrations.class ); if ( jdbcTypesAnn != null ) { final JdbcTypeRegistration[] registrations = jdbcTypesAnn.value(); - for ( int i = 0; i < registrations.length; i++ ) { - handleJdbcTypeRegistration( context, managedBeanRegistry, registrations[ i ] ); + for ( JdbcTypeRegistration registration : registrations ) { + handleJdbcTypeRegistration(context, managedBeanRegistry, registration); } } } @@ -979,20 +1075,17 @@ public final class AnnotationBinder { } private static void bindEmbeddableInstantiatorRegistrations(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - final ManagedBeanRegistry managedBeanRegistry = context.getBootstrapContext() - .getServiceRegistry() - .getService( ManagedBeanRegistry.class ); - - final EmbeddableInstantiatorRegistration instantiatorReg = annotatedElement.getAnnotation( EmbeddableInstantiatorRegistration.class ); + final EmbeddableInstantiatorRegistration instantiatorReg = + annotatedElement.getAnnotation( EmbeddableInstantiatorRegistration.class ); if ( instantiatorReg != null ) { - handleEmbeddableInstantiatorRegistration( context, managedBeanRegistry, instantiatorReg ); + handleEmbeddableInstantiatorRegistration( context, instantiatorReg ); } else { final EmbeddableInstantiatorRegistrations annotation = annotatedElement.getAnnotation( EmbeddableInstantiatorRegistrations.class ); if ( annotation != null ) { final EmbeddableInstantiatorRegistration[] registrations = annotation.value(); - for ( int i = 0; i < registrations.length; i++ ) { - handleEmbeddableInstantiatorRegistration( context, managedBeanRegistry, registrations[i] ); + for ( EmbeddableInstantiatorRegistration registration : registrations ) { + handleEmbeddableInstantiatorRegistration(context, registration); } } } @@ -1000,7 +1093,6 @@ public final class AnnotationBinder { private static void handleEmbeddableInstantiatorRegistration( MetadataBuildingContext context, - ManagedBeanRegistry managedBeanRegistry, EmbeddableInstantiatorRegistration annotation) { context.getMetadataCollector().registerEmbeddableInstantiator( annotation.embeddableClass(), @@ -1129,24 +1221,29 @@ public final class AnnotationBinder { } private static void processIdPropertiesIfNotAlready( - Map inheritanceStatePerClass, - MetadataBuildingContext context, PersistentClass persistentClass, + InheritanceState inheritanceState, + MetadataBuildingContext context, EntityBinder entityBinder, PropertyHolder propertyHolder, HashMap classGenerators, + Set idPropertiesIfIdClass, InheritanceState.ElementsToProcess elementsToProcess, - boolean subclassAndSingleTableStrategy, - Set idPropertiesIfIdClass) { + Map inheritanceStatePerClass) { + Set missingIdProperties = new HashSet<>( idPropertiesIfIdClass ); for ( PropertyData propertyAnnotatedElement : elementsToProcess.getElements() ) { String propertyName = propertyAnnotatedElement.getPropertyName(); if ( !idPropertiesIfIdClass.contains( propertyName ) ) { + boolean subclassAndSingleTableStrategy = + inheritanceState.getType() == InheritanceType.SINGLE_TABLE + && inheritanceState.hasParents(); + Nullability nullability = subclassAndSingleTableStrategy + ? Nullability.FORCED_NULL + : Nullability.NO_CONSTRAINT; processElementAnnotations( propertyHolder, - subclassAndSingleTableStrategy - ? Nullability.FORCED_NULL - : Nullability.NO_CONSTRAINT, + nullability, propertyAnnotatedElement, classGenerators, entityBinder, @@ -1184,17 +1281,14 @@ public final class AnnotationBinder { InheritanceState.ElementsToProcess elementsToProcess, Set idPropertiesIfIdClass, MetadataBuildingContext context) { - /* - * We are looking for @IdClass - * In general we map the id class as identifier using the mapping metadata of the main entity's properties - * and we create an identifier mapper containing the id properties of the main entity - * - * In JPA 2, there is a shortcut if the id class is the Pk of the associated class pointed to by the id - * it ought to be treated as an embedded and not a real IdClass (at least in the Hibernate's internal way) - */ + + // We are looking for @IdClass + // In general we map the id class as identifier using the mapping metadata of the main entity's + // properties and we create an identifier mapper containing the id properties of the main entity XClass classWithIdClass = inheritanceState.getClassWithIdClass( false ); if ( classWithIdClass != null ) { IdClass idClass = classWithIdClass.getAnnotation( IdClass.class ); + //noinspection unchecked XClass compositeClass = context.getBootstrapContext().getReflectionManager().toXClass( idClass.value() ); PropertyData inferredData = new PropertyPreloadedData( entityBinder.getPropertyAccessType(), "id", compositeClass @@ -1203,8 +1297,9 @@ public final class AnnotationBinder { entityBinder.getPropertyAccessType(), "id", classWithIdClass ); AccessType propertyAccessor = entityBinder.getPropertyAccessor( compositeClass ); - //In JPA 2, there is a shortcut if the IdClass is the Pk of the associated class pointed to by the id - //it ought to be treated as an embedded and not a real IdClass (at least in the Hibernate's internal way) + + // In JPA 2, there is a shortcut if the IdClass is the Pk of the associated class pointed to by the id + // it ought to be treated as an embedded and not a real IdClass (at least in Hibernate's internal way) final boolean isFakeIdClass = isIdClassPkOfTheAssociatedEntity( elementsToProcess, compositeClass, @@ -1219,35 +1314,26 @@ public final class AnnotationBinder { return false; } - boolean isComponent = true; - String generatorType = "assigned"; - String generator = BinderHelper.ANNOTATION_STRING_DEFAULT; - boolean ignoreIdAnnotations = entityBinder.isIgnoreIdAnnotations(); entityBinder.setIgnoreIdAnnotations( true ); propertyHolder.setInIdClass( true ); bindIdClass( - generatorType, - generator, inferredData, baseInferredData, - null, propertyHolder, - isComponent, propertyAccessor, entityBinder, - true, - false, context, inheritanceStatePerClass ); propertyHolder.setInIdClass( null ); - inferredData = new PropertyPreloadedData( - propertyAccessor, PropertyPath.IDENTIFIER_MAPPER_PROPERTY, compositeClass - ); Component mapper = fillComponent( propertyHolder, - inferredData, + new PropertyPreloadedData( + propertyAccessor, + PropertyPath.IDENTIFIER_MAPPER_PROPERTY, + compositeClass + ), baseInferredData, propertyAccessor, false, @@ -1262,8 +1348,8 @@ public final class AnnotationBinder { entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations ); persistentClass.setIdentifierMapper( mapper ); - //If id definition is on a mapped superclass, update the mapping - final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull( + // If id definition is on a mapped superclass, update the mapping + final org.hibernate.mapping.MappedSuperclass superclass = getMappedSuperclassOrNull( classWithIdClass, inheritanceStatePerClass, context @@ -1272,7 +1358,7 @@ public final class AnnotationBinder { superclass.setDeclaredIdentifierMapper( mapper ); } else { - //we are for sure on the entity + // we are for sure on the entity persistentClass.setDeclaredIdentifierMapper( mapper ); } @@ -1324,10 +1410,10 @@ public final class AnnotationBinder { } else { - final XClass idClass = context.getBootstrapContext().getReflectionManager().toXClass( - associatedClassWithIdClass.getAnnotation( IdClass.class ).value() - ); - return idClass.equals( compositeClass ); + IdClass idClass = associatedClassWithIdClass.getAnnotation(IdClass.class); + //noinspection unchecked + return context.getBootstrapContext().getReflectionManager().toXClass( idClass.value() ) + .equals( compositeClass ); } } else { @@ -1335,19 +1421,6 @@ public final class AnnotationBinder { } } - private static void applyCacheSettings(EntityBinder binder, XClass clazzToProcess, MetadataBuildingContext context) { - binder.applyCaching( - clazzToProcess, - determineSharedCacheMode( context ), - context - - ); - } - - private static SharedCacheMode determineSharedCacheMode(MetadataBuildingContext context) { - return context.getBuildingOptions().getSharedCacheMode(); - } - private static PersistentClass makePersistentClass( InheritanceState inheritanceState, PersistentClass superEntity, @@ -1356,17 +1429,17 @@ public final class AnnotationBinder { if ( !inheritanceState.hasParents() ) { return new RootClass( metadataBuildingContext ); } - else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) { - return new SingleTableSubclass( superEntity, metadataBuildingContext ); - } - else if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) { - return new JoinedSubclass( superEntity, metadataBuildingContext ); - } - else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) ) { - return new UnionSubclass( superEntity, metadataBuildingContext ); - } else { - throw new AssertionFailure( "Unknown inheritance type: " + inheritanceState.getType() ); + switch ( inheritanceState.getType() ) { + case SINGLE_TABLE: + return new SingleTableSubclass( superEntity, metadataBuildingContext ); + case JOINED: + return new JoinedSubclass( superEntity, metadataBuildingContext ); + case TABLE_PER_CLASS: + return new UnionSubclass( superEntity, metadataBuildingContext ); + default: + throw new AssertionFailure( "Unknown inheritance type: " + inheritanceState.getType() ); + } } } @@ -1375,9 +1448,10 @@ public final class AnnotationBinder { MetadataBuildingContext context, InheritanceState inheritanceState, PersistentClass superEntity) { + AnnotatedJoinColumn[] inheritanceJoinedColumns = null; final boolean hasJoinedColumns = inheritanceState.hasParents() - && InheritanceType.JOINED.equals( inheritanceState.getType() ); + && InheritanceType.JOINED == inheritanceState.getType(); if ( hasJoinedColumns ) { //@Inheritance(JOINED) subclass need to link back to the super entity PrimaryKeyJoinColumns jcsAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class ); @@ -1444,29 +1518,10 @@ public final class AnnotationBinder { return superEntity; } - private static boolean isEntityClassType(XClass clazzToProcess, AnnotatedClassType classType) { - if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) //will be processed by their subentities - || AnnotatedClassType.NONE.equals( classType ) //to be ignored - || AnnotatedClassType.EMBEDDABLE.equals( classType ) //allow embeddable element declaration - ) { - return false; - } - - if ( !classType.equals( AnnotatedClassType.ENTITY ) ) { - throw new AnnotationException( - "Annotated class should have a @jakarta.persistence.Entity, @jakarta.persistence.Embeddable or @jakarta.persistence.EmbeddedSuperclass annotation: " + clazzToProcess - .getName() - ); - } - - return true; - } - - /* + /** * Process the filters defined on the given class, as well as all filters defined * on the MappedSuperclass(s) in the inheritance hierarchy */ - private static void bindFiltersAndFilterDefs( XClass annotatedClass, EntityBinder entityBinder, @@ -1477,7 +1532,7 @@ public final class AnnotationBinder { XClass classToProcess = annotatedClass.getSuperclass(); while ( classToProcess != null ) { AnnotatedClassType classType = context.getMetadataCollector().getClassType( classToProcess ); - if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) { + if ( AnnotatedClassType.MAPPED_SUPERCLASS == classType ) { bindFilters( classToProcess, entityBinder, context ); } else { @@ -1485,7 +1540,6 @@ public final class AnnotationBinder { } classToProcess = classToProcess.getSuperclass(); } - } private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder entityBinder, MetadataBuildingContext context) { @@ -1548,14 +1602,17 @@ public final class AnnotationBinder { private static JdbcMapping resolveFilterParamType(Class type, MetadataBuildingContext context) { if ( UserType.class.isAssignableFrom( type ) ) { + //noinspection unchecked return resolveUserType( (Class>) type, context ); } if ( AttributeConverter.class.isAssignableFrom( type ) ) { + //noinspection unchecked return resolveAttributeConverter( (Class>) type, context ); } if ( JavaType.class.isAssignableFrom( type ) ) { + //noinspection unchecked return resolveJavaType( (Class>) type, context ); } @@ -1576,8 +1633,7 @@ public final class AnnotationBinder { final ManagedBean> bean = beanRegistry.getBean( type ); final UserType userType = bean.getBeanInstance(); - //noinspection rawtypes - return new CustomType( userType, context.getBootstrapContext().getTypeConfiguration() ); + return new CustomType<>( userType, context.getBootstrapContext().getTypeConfiguration() ); } private static JdbcMapping resolveAttributeConverter(Class> type, MetadataBuildingContext context) { @@ -1766,7 +1822,7 @@ public final class AnnotationBinder { final XAnnotatedElement element = propertyAnnotatedElement.getProperty(); if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) { inFlightPropertyDataList.add( 0, propertyAnnotatedElement ); - /** + /* * The property must be put in hibernate.properties as it's a system wide property. Fixable? * TODO support true/false/default on the property instead of present / not present * TODO is @Column mandatory? @@ -1777,7 +1833,7 @@ public final class AnnotationBinder { String columnName = element.getAnnotation( Column.class ).name(); for ( XProperty prop : declaringClass.getDeclaredProperties( AccessType.FIELD.getType() ) ) { if ( !prop.isAnnotationPresent( MapsId.class ) ) { - /** + /* * The detection of a configured individual JoinColumn differs between Annotation * and XML configuration processing. */ @@ -1859,7 +1915,7 @@ public final class AnnotationBinder { } } - /** + /* * inSecondPass can only be used to apply right away the second pass of a composite-element * Because it's a value type, there is no bidirectional association, hence second pass * ordering does not matter @@ -1952,7 +2008,7 @@ public final class AnnotationBinder { rootClass.setVersion( prop ); //If version is on a mapped superclass, update the mapping - final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull( + final org.hibernate.mapping.MappedSuperclass superclass = getMappedSuperclassOrNull( inferredData.getDeclaringClass(), inheritanceStatePerClass, context @@ -2007,10 +2063,9 @@ public final class AnnotationBinder { // is mandatory (even if the association has optional=true). // If a @MapsId association has optional=true and is mapped with @NotFound(IGNORE) then // the association is optional. - final boolean mandatory = - !ann.optional() || - property.isAnnotationPresent( Id.class ) || - ( property.isAnnotationPresent( MapsId.class ) && !ignoreNotFound ); + final boolean mandatory = !ann.optional() + || property.isAnnotationPresent( Id.class ) + || property.isAnnotationPresent( MapsId.class ) && !ignoreNotFound; bindManyToOne( getCascadeStrategy( ann.cascade(), hibernateCascade, false, forcePersist ), joinColumns, @@ -2040,9 +2095,8 @@ public final class AnnotationBinder { } //FIXME support a proper PKJCs - final boolean hasPkjc = property.isAnnotationPresent( PrimaryKeyJoinColumn.class ) + boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class ) || property.isAnnotationPresent( PrimaryKeyJoinColumns.class ); - boolean trueOneToOne = hasPkjc; Cascade hibernateCascade = property.getAnnotation( Cascade.class ); NotFound notFound = property.getAnnotation( NotFound.class ); boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE ); @@ -2142,7 +2196,8 @@ public final class AnnotationBinder { } final OrderColumn orderColumnAnnotation = property.getAnnotation( OrderColumn.class ); - final org.hibernate.annotations.IndexColumn indexColumnAnnotation = property.getAnnotation( org.hibernate.annotations.IndexColumn.class ); + final org.hibernate.annotations.IndexColumn indexColumnAnnotation = + property.getAnnotation( org.hibernate.annotations.IndexColumn.class ); final ListIndexBase indexBaseAnnotation = property.getAnnotation( ListIndexBase.class ); final IndexColumn indexColumn = IndexColumn.fromAnnotations( @@ -2199,7 +2254,7 @@ public final class AnnotationBinder { || property.isAnnotationPresent( Formula.class ) ) { Column ann = property.getAnnotation( Column.class ); Formula formulaAnn = getOverridableAnnotation( property, Formula.class, context ); - elementColumns = AnnotatedColumn.buildColumnFromAnnotation( + elementColumns = buildColumnFromAnnotation( new Column[] { ann }, formulaAnn, comment, @@ -2212,7 +2267,7 @@ public final class AnnotationBinder { } else if ( property.isAnnotationPresent( Columns.class ) ) { Columns anns = property.getAnnotation( Columns.class ); - elementColumns = AnnotatedColumn.buildColumnFromAnnotation( + elementColumns = buildColumnFromAnnotation( anns.columns(), null, comment, @@ -2224,7 +2279,7 @@ public final class AnnotationBinder { ); } else { - elementColumns = AnnotatedColumn.buildColumnFromAnnotation( + elementColumns = buildColumnFromAnnotation( null, null, comment, @@ -2235,68 +2290,28 @@ public final class AnnotationBinder { context ); } - { - Column[] keyColumns; - if ( property.isAnnotationPresent( MapKeyColumn.class ) ) { - keyColumns = new Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) }; - } - else { - keyColumns = null; - } - AnnotatedColumn[] mapColumns = AnnotatedColumn.buildColumnFromAnnotation( - keyColumns, - null, - comment, - Nullability.FORCED_NOT_NULL, - propertyHolder, - inferredData, - "_KEY", - entityBinder.getSecondaryTables(), - context - ); - collectionBinder.setMapKeyColumns( mapColumns ); - } - { - JoinColumn[] joinKeyColumns = null; - if ( property.isAnnotationPresent( MapKeyJoinColumns.class ) ) { - final MapKeyJoinColumn[] mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class ) - .value(); - joinKeyColumns = new JoinColumn[mapKeyJoinColumns.length]; - int index = 0; - for ( MapKeyJoinColumn joinColumn : mapKeyJoinColumns ) { - joinKeyColumns[index] = new MapKeyJoinColumnDelegator( joinColumn ); - index++; - } - if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { - throw new AnnotationException( - "@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: " - + BinderHelper.getPath( propertyHolder, inferredData ) - ); - } - } - else if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { - joinKeyColumns = new JoinColumn[] { - new MapKeyJoinColumnDelegator( - property.getAnnotation( - MapKeyJoinColumn.class - ) - ) - }; - } + JoinColumn[] joinKeyColumns = mapKeyColumns( + propertyHolder, + inferredData, + entityBinder, + context, + property, + collectionBinder, + comment + ); - AnnotatedJoinColumn[] mapJoinColumns = AnnotatedJoinColumn.buildJoinColumnsWithDefaultColumnSuffix( - joinKeyColumns, - comment, - null, - entityBinder.getSecondaryTables(), - propertyHolder, - inferredData.getPropertyName(), - "_KEY", - context - ); - collectionBinder.setMapKeyManyToManyColumns( mapJoinColumns ); - } + AnnotatedJoinColumn[] mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix( + joinKeyColumns, + comment, + null, + entityBinder.getSecondaryTables(), + propertyHolder, + inferredData.getPropertyName(), + "_KEY", + context + ); + collectionBinder.setMapKeyManyToManyColumns( mapJoinColumns ); //potential element collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) ); @@ -2319,6 +2334,7 @@ public final class AnnotationBinder { } collectionBinder.setFkJoinColumns( joinColumns ); mappedBy = oneToManyAnn.mappedBy(); + //noinspection unchecked collectionBinder.setTargetEntity( context.getBootstrapContext().getReflectionManager().toXClass( oneToManyAnn.targetEntity() ) ); @@ -2346,6 +2362,7 @@ public final class AnnotationBinder { } else if ( manyToManyAnn != null ) { mappedBy = manyToManyAnn.mappedBy(); + //noinspection unchecked collectionBinder.setTargetEntity( context.getBootstrapContext().getReflectionManager().toXClass( manyToManyAnn.targetEntity() ) ); @@ -2384,7 +2401,7 @@ public final class AnnotationBinder { collectionBinder.setUpdatable( false ); } if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary - HashMap localGenerators = ( HashMap ) classGenerators.clone(); + HashMap localGenerators = new HashMap<>( classGenerators ); localGenerators.putAll( buildGenerators( property, context ) ); collectionBinder.setLocalGenerators( localGenerators ); @@ -2414,18 +2431,13 @@ public final class AnnotationBinder { isOverridden = true; final InheritanceState state = inheritanceStatePerClass.get( overridingProperty.getClassOrElement() ); if ( state != null ) { - isComponent = isComponent || state.hasIdClassOrEmbeddedId(); + isComponent = state.hasIdClassOrEmbeddedId(); } //Get the new column columns = columnsBuilder.overrideColumnFromMapperOrMapsIdProperty( isId ); } } - if ( ! isComponent ) { - if ( property.isAnnotationPresent( Embedded.class ) ) { - - } - } isComponent = isComponent || property.isAnnotationPresent( Embedded.class ) || property.isAnnotationPresent( EmbeddedId.class ) @@ -2520,8 +2532,7 @@ public final class AnnotationBinder { context.getMetadataCollector().addSecondPass( secondPass ); } else { - Map localGenerators = (HashMap) classGenerators - .clone(); + Map localGenerators = new HashMap<>(classGenerators); localGenerators.put( foreignGenerator.getName(), foreignGenerator ); BinderHelper.makeIdGenerator( @@ -2550,25 +2561,98 @@ public final class AnnotationBinder { } } } - //init index + + addIndexes(inSecondPass, property, columns, joinColumns); + + addNaturalIds(inSecondPass, property, columns, joinColumns); + } + + private static JoinColumn[] mapKeyColumns( + PropertyHolder propertyHolder, + PropertyData inferredData, + EntityBinder entityBinder, + MetadataBuildingContext context, + XProperty property, + CollectionBinder collectionBinder, + Comment comment) { + Column[] keyColumns; + if ( property.isAnnotationPresent( MapKeyColumn.class ) ) { + keyColumns = new Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) }; + } + else { + keyColumns = null; + } + + AnnotatedColumn[] mapColumns = buildColumnFromAnnotation( + keyColumns, + null, + comment, + Nullability.FORCED_NOT_NULL, + propertyHolder, + inferredData, + "_KEY", + entityBinder.getSecondaryTables(), + context + ); + collectionBinder.setMapKeyColumns( mapColumns ); + + JoinColumn[] joinKeyColumns = null; + if ( property.isAnnotationPresent( MapKeyJoinColumns.class ) ) { + final MapKeyJoinColumn[] mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class ).value(); + joinKeyColumns = new JoinColumn[mapKeyJoinColumns.length]; + int index = 0; + for ( MapKeyJoinColumn joinColumn : mapKeyJoinColumns ) { + joinKeyColumns[index] = new MapKeyJoinColumnDelegator( joinColumn ); + index++; + } + if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { + throw new AnnotationException( + "@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: " + + BinderHelper.getPath(propertyHolder, inferredData) + ); + } + } + else if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { + joinKeyColumns = new JoinColumn[] { + new MapKeyJoinColumnDelegator( + property.getAnnotation( + MapKeyJoinColumn.class + ) + ) + }; + } + return joinKeyColumns; + } + + private static void addIndexes( + boolean inSecondPass, + XProperty property, + AnnotatedColumn[] columns, + AnnotatedJoinColumn[] joinColumns) { //process indexes after everything: in second pass, many to one has to be done before indexes Index index = property.getAnnotation( Index.class ); if ( index != null ) { if ( joinColumns != null ) { - for ( AnnotatedColumn column : joinColumns ) { - column.addIndex( index, inSecondPass ); + for ( AnnotatedColumn column : joinColumns) { + column.addIndex( index, inSecondPass); } } else { if ( columns != null ) { - for ( AnnotatedColumn column : columns ) { - column.addIndex( index, inSecondPass ); + for ( AnnotatedColumn column : columns) { + column.addIndex( index, inSecondPass); } } } } + } + private static void addNaturalIds( + boolean inSecondPass, + XProperty property, + AnnotatedColumn[] columns, + AnnotatedJoinColumn[] joinColumns) { // Natural ID columns must reside in one single UniqueKey within the Table. // For now, simply ensure consistent naming. // TODO: AFAIK, there really isn't a reason for these UKs to be created @@ -2576,15 +2660,15 @@ public final class AnnotationBinder { NaturalId naturalIdAnn = property.getAnnotation( NaturalId.class ); if ( naturalIdAnn != null ) { if ( joinColumns != null ) { - for ( AnnotatedColumn column : joinColumns ) { + for ( AnnotatedColumn column : joinColumns) { String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" ); - column.addUniqueKey( keyName, inSecondPass ); + column.addUniqueKey( keyName, inSecondPass); } } else { - for ( AnnotatedColumn column : columns ) { + for ( AnnotatedColumn column : columns) { String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" ); - column.addUniqueKey( keyName, inSecondPass ); + column.addUniqueKey( keyName, inSecondPass); } } } @@ -2599,17 +2683,19 @@ public final class AnnotationBinder { return null; } - final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = + property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( propertyAnnotation != null ) { return propertyAnnotation.value(); } - final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = returnedClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = + returnedClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( classAnnotation != null ) { return classAnnotation.value(); } - final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( returnedClass ); + final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( returnedClass ); if ( embeddableClass != null ) { return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( embeddableClass ); } @@ -2689,8 +2775,7 @@ public final class AnnotationBinder { } else { //clone classGenerator and override with local values - HashMap localGenerators = (HashMap) classGenerators - .clone(); + HashMap localGenerators = new HashMap<>( classGenerators ); localGenerators.putAll( buildGenerators( idXProperty, buildingContext ) ); BinderHelper.makeIdGenerator( idValue, @@ -2715,9 +2800,9 @@ public final class AnnotationBinder { return buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter().determineGeneratorName( generatedValueAnn.strategy(), new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() { - Class javaType = null; + Class javaType = null; @Override - public Class getIdType() { + public Class getIdType() { if ( javaType == null ) { javaType = buildingContext .getBootstrapContext() @@ -2874,7 +2959,6 @@ public final class AnnotationBinder { ); } } - XProperty property = inferredData.getProperty(); PropertyBinder binder = new PropertyBinder(); binder.setDeclaringClass(inferredData.getDeclaringClass()); binder.setName( inferredData.getPropertyName() ); @@ -2932,7 +3016,7 @@ public final class AnnotationBinder { Class customInstantiatorImpl, MetadataBuildingContext buildingContext, Map inheritanceStatePerClass) { - /** + /* * inSecondPass can only be used to apply right away the second pass of a composite-element * Because it's a value type, there is no bidirectional association, hence second pass * ordering does not matter @@ -2941,7 +3025,7 @@ public final class AnnotationBinder { String subpath = BinderHelper.getPath( propertyHolder, inferredData ); LOG.tracev( "Binding component with path: {0}", subpath ); - PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder( + PropertyHolder subHolder = buildPropertyHolder( comp, subpath, inferredData, @@ -3007,13 +3091,13 @@ public final class AnnotationBinder { || entityPropertyData.getProperty().isAnnotationPresent( OneToOne.class ); final boolean isOfDifferentType = !entityPropertyData.getClassOrElement() .equals( idClassPropertyData.getClassOrElement() ); - if ( hasXToOneAnnotation && isOfDifferentType ) { - //don't replace here as we need to use the actual original return type - //the annotation overriding will be dealt with by a mechanism similar to @MapsId - } - else { + if ( !hasXToOneAnnotation || !isOfDifferentType ) { classElements.set( i, entityPropertyData ); //this works since they are in the same order } +// else { + //don't replace here as we need to use the actual original return type + //the annotation overriding will be dealt with by a mechanism similar to @MapsId +// } } else { classElements.set( i, entityPropertyData ); //this works since they are in the same order @@ -3101,17 +3185,11 @@ public final class AnnotationBinder { } private static void bindIdClass( - String generatorType, - String generatorName, PropertyData inferredData, PropertyData baseInferredData, - AnnotatedColumn[] columns, PropertyHolder propertyHolder, - boolean isComposite, AccessType propertyAccessor, EntityBinder entityBinder, - boolean isEmbedded, - boolean isIdentifierMapper, MetadataBuildingContext buildingContext, Map inheritanceStatePerClass) { @@ -3119,64 +3197,43 @@ public final class AnnotationBinder { * Fill simple value and property since and Id is a property */ PersistentClass persistentClass = propertyHolder.getPersistentClass(); - if ( !( persistentClass instanceof RootClass ) ) { + if ( !(persistentClass instanceof RootClass) ) { throw new AnnotationException( "Unable to define/override @Id(s) on a subclass: " + propertyHolder.getEntityName() ); } - RootClass rootClass = ( RootClass ) persistentClass; - String persistentClassName = rootClass.getClassName(); - SimpleValue id; - final String propertyName = inferredData.getPropertyName(); - if ( isComposite ) { - id = fillComponent( - propertyHolder, - inferredData, - baseInferredData, - propertyAccessor, - false, - entityBinder, - isEmbedded, - isIdentifierMapper, - false, - null, - buildingContext, - inheritanceStatePerClass - ); - Component componentId = ( Component ) id; - componentId.setKey( true ); - if ( rootClass.getIdentifier() != null ) { - throw new AnnotationException( componentId.getComponentClassName() + " must not have @Id properties when used as an @EmbeddedId" ); - } - if ( componentId.getPropertySpan() == 0 ) { - throw new AnnotationException( componentId.getComponentClassName() + " has no persistent id property" ); - } - //tuplizers - XProperty property = inferredData.getProperty(); + RootClass rootClass = (RootClass) persistentClass; + Component id = fillComponent( + propertyHolder, + inferredData, + baseInferredData, + propertyAccessor, + false, + entityBinder, + true, + false, + false, + null, + buildingContext, + inheritanceStatePerClass + ); + id.setKey( true ); + if ( rootClass.getIdentifier() != null ) { + throw new AnnotationException( id.getComponentClassName() + " must not have @Id properties when used as an @EmbeddedId" ); + } + if ( id.getPropertySpan() == 0 ) { + throw new AnnotationException( id.getComponentClassName() + " has no persistent id property" ); } - else { - //TODO I think this branch is never used. Remove. - for ( AnnotatedColumn column : columns ) { - column.forceNotNull(); //this is an id - } - final BasicValueBinder value = new BasicValueBinder( BasicValueBinder.Kind.ATTRIBUTE, buildingContext ); - value.setPropertyName( propertyName ); - value.setReturnedClassName( inferredData.getTypeName() ); - value.setColumns( columns ); - value.setPersistentClassName( persistentClassName ); - value.setType( inferredData.getProperty(), inferredData.getClassOrElement(), persistentClassName, null ); - value.setAccessType( propertyAccessor ); - id = value.make(); - } rootClass.setIdentifier( id ); + if ( isGlobalGeneratorNameGlobal( buildingContext ) ) { SecondPass secondPass = new IdGeneratorResolverSecondPass( id, inferredData.getProperty(), - generatorType, - generatorName, + DEFAULT_ID_GEN_STRATEGY, + "", buildingContext ); buildingContext.getMetadataCollector().addSecondPass( secondPass ); @@ -3185,38 +3242,14 @@ public final class AnnotationBinder { BinderHelper.makeIdGenerator( id, inferredData.getProperty(), - generatorType, - generatorName, + DEFAULT_ID_GEN_STRATEGY, + "", buildingContext, Collections.emptyMap() ); } - if ( isEmbedded ) { - rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null ); - } - else { - PropertyBinder binder = new PropertyBinder(); - binder.setName( propertyName ); - binder.setValue( id ); - binder.setAccessType( inferredData.getDefaultAccess() ); - binder.setProperty( inferredData.getProperty() ); - Property prop = binder.makeProperty(); - rootClass.setIdentifierProperty( prop ); - //if the id property is on a superclass, update the metamodel - final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull( - inferredData.getDeclaringClass(), - inheritanceStatePerClass, - buildingContext - ); - if ( superclass != null ) { - superclass.setDeclaredIdentifierProperty( prop ); - } - else { - //we know the property is on the actual entity - rootClass.setDeclaredIdentifierProperty( prop ); - } - } + rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null ); } private static PropertyData getUniqueIdPropertyFromBaseClass( @@ -3361,7 +3394,7 @@ public final class AnnotationBinder { } } - protected static void defineFetchingStrategy(ToOne toOne, XProperty property) { + static void defineFetchingStrategy(ToOne toOne, XProperty property) { LazyToOne lazy = property.getAnnotation( LazyToOne.class ); Fetch fetch = property.getAnnotation( Fetch.class ); ManyToOne manyToOne = property.getAnnotation( ManyToOne.class ); @@ -3631,14 +3664,12 @@ public final class AnnotationBinder { cascade.append( "," ).append( "evict" ); break; case DELETE: + case REMOVE: cascade.append( "," ).append( "delete" ); break; case DELETE_ORPHAN: cascade.append( "," ).append( "delete-orphan" ); break; - case REMOVE: - cascade.append( "," ).append( "delete" ); - break; } } return cascade.length() > 0 ? @@ -3647,12 +3678,7 @@ public final class AnnotationBinder { } public static FetchMode getFetchMode(FetchType fetch) { - if ( fetch == FetchType.EAGER ) { - return FetchMode.JOIN; - } - else { - return FetchMode.SELECT; - } + return fetch == FetchType.EAGER ? FetchMode.JOIN : FetchMode.SELECT; } public static void bindForeignKeyNameAndDefinition( @@ -3667,7 +3693,7 @@ public final class AnnotationBinder { || joinColumn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) || ( joinColumns != null && ( joinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT || joinColumns.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) ) { - value.setForeignKeyName( "none" ); + value.disableForeignKey(); } else { final ForeignKey fk = property.getAnnotation( ForeignKey.class ); @@ -3677,7 +3703,7 @@ public final class AnnotationBinder { else { if ( fkOverride != null && ( fkOverride.value() == ConstraintMode.NO_CONSTRAINT || fkOverride.value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) { - value.setForeignKeyName( "none" ); + value.disableForeignKey(); } else if ( fkOverride != null ) { value.setForeignKeyName( StringHelper.nullIfEmpty( fkOverride.name() ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java index 0a578055a2..b94cc71dac 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java @@ -29,6 +29,7 @@ import org.hibernate.annotations.SqlFragmentAlias; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; +import org.hibernate.boot.model.IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.cfg.annotations.BasicValueBinder; @@ -550,8 +551,7 @@ public class BinderHelper { id.setIdentifierGeneratorStrategy( identifierGeneratorStrategy ); } //checkIfMatchingGenerator(gen, generatorType, generatorName); - for ( Object o : gen.getParameters().entrySet() ) { - Map.Entry elt = (Map.Entry) o; + for ( Map.Entry elt : gen.getParameters().entrySet() ) { if ( elt.getKey() == null ) { continue; } @@ -594,7 +594,8 @@ public class BinderHelper { } } - final IdentifierGeneratorDefinition globalDefinition = buildingContext.getMetadataCollector().getIdentifierGenerator( name ); + final IdentifierGeneratorDefinition globalDefinition = + buildingContext.getMetadataCollector().getIdentifierGenerator( name ); if ( globalDefinition != null ) { return globalDefinition; } @@ -615,7 +616,8 @@ public class BinderHelper { return new IdentifierGeneratorDefinition( "assigned", "assigned" ); } - final IdGeneratorStrategyInterpreter generationInterpreter = buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter(); + final IdGeneratorStrategyInterpreter generationInterpreter = + buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter(); final GenerationType generationType = interpretGenerationType( generatedValueAnn ); @@ -746,9 +748,9 @@ public class BinderHelper { else { strategyName = generationInterpreter.determineGeneratorName( generationType, - new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() { + new GeneratorNameDeterminationContext() { @Override - public Class getIdType() { + public Class getIdType() { return buildingContext .getBootstrapContext() .getReflectionManager() @@ -812,7 +814,8 @@ public class BinderHelper { value.setLazy( lazy ); value.setCascadeDeleteEnabled( cascadeOnDelete ); - final BasicValueBinder discriminatorValueBinder = new BasicValueBinder<>( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context ); + final BasicValueBinder discriminatorValueBinder = + new BasicValueBinder<>( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context ); final AnnotatedColumn[] discriminatorColumns = AnnotatedColumn.buildColumnFromAnnotation( new jakarta.persistence.Column[] { discriminatorColumn }, @@ -864,7 +867,10 @@ public class BinderHelper { final BasicValue keyDescriptor = keyValueBinder.make(); value.setKey( keyDescriptor ); keyValueBinder.fillSimpleValue(); - AnnotatedColumn.checkPropertyConsistency( keyColumns, propertyHolder.getEntityName() + "." + inferredData.getPropertyName() ); + AnnotatedColumn.checkPropertyConsistency( + keyColumns, + propertyHolder.getEntityName() + "." + inferredData.getPropertyName() + ); keyColumns[0].linkWithValue( keyDescriptor ); return value; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java b/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java index 5dbe45450d..4076488e6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java @@ -38,12 +38,13 @@ import static org.hibernate.cfg.AnnotationBinder.getOverridableAnnotation; * @author Brett Meyer */ class ColumnsBuilder { - private PropertyHolder propertyHolder; - private Nullability nullability; - private XProperty property; - private PropertyData inferredData; - private EntityBinder entityBinder; - private MetadataBuildingContext buildingContext; + + private final PropertyHolder propertyHolder; + private final Nullability nullability; + private final XProperty property; + private final PropertyData inferredData; + private final EntityBinder entityBinder; + private final MetadataBuildingContext buildingContext; private AnnotatedColumn[] columns; private AnnotatedJoinColumn[] joinColumns; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java index 25a0c372c5..0adf97cd42 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java @@ -27,7 +27,7 @@ public class CreateKeySecondPass implements SecondPass { this.joinedSubClass = joinedSubClass; } - public void doSecondPass(Map persistentClasses) throws MappingException { + public void doSecondPass(Map persistentClasses) { if ( rootClass != null ) { rootClass.createPrimaryKey(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/InheritanceState.java b/hibernate-core/src/main/java/org/hibernate/cfg/InheritanceState.java index a03c80ff4a..253bdbb379 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/InheritanceState.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/InheritanceState.java @@ -44,9 +44,9 @@ public class InheritanceState { private boolean hasParents = false; private InheritanceType type; private boolean isEmbeddableSuperclass = false; - private Map inheritanceStatePerClass; - private List classesToProcessForMappedSuperclass = new ArrayList<>(); - private MetadataBuildingContext buildingContext; + private final Map inheritanceStatePerClass; + private final List classesToProcessForMappedSuperclass = new ArrayList<>(); + private final MetadataBuildingContext buildingContext; private AccessType accessType; private ElementsToProcess elementsToProcess; private Boolean hasIdClassOrEmbeddedId; @@ -195,17 +195,15 @@ public class InheritanceState { } /* - * Get the annotated elements and determine access type from hierarchy, guessing from @Id or @EmbeddedId presence if not - * specified. + * Get the annotated elements and determine access type from hierarchy, + * guessing from @Id or @EmbeddedId presence if not specified. * Change EntityBinder by side effect */ - public ElementsToProcess getElementsToProcess() { if ( elementsToProcess == null ) { InheritanceState inheritanceState = inheritanceStatePerClass.get( clazz ); assert !inheritanceState.isEmbeddableSuperclass(); - getMappedSuperclassesTillNextEntityOrdered(); accessType = determineDefaultAccessType(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java index b1d879cfab..8249645661 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java @@ -8,7 +8,6 @@ package org.hibernate.cfg.annotations; import java.util.Comparator; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -184,7 +183,7 @@ public abstract class CollectionBinder { private TableBinder tableBinder; private AnnotatedColumn[] mapKeyColumns; private AnnotatedJoinColumn[] mapKeyManyToManyColumns; - protected HashMap localGenerators; + protected Map localGenerators; protected Map inheritanceStatePerClass; private XClass declaringClass; private boolean declaringClassSet; @@ -1119,8 +1118,7 @@ public abstract class CollectionBinder { if ( jpaOrderBy != null ) { final String orderByFragment = buildOrderByClauseFromHql( jpaOrderBy.value(), - associatedClass, - collection.getRole() + associatedClass ); if ( StringHelper.isNotEmpty( orderByFragment ) ) { collection.setOrderBy( orderByFragment ); @@ -1337,7 +1335,7 @@ public abstract class CollectionBinder { } } - private static String buildOrderByClauseFromHql(String orderByFragment, PersistentClass associatedClass, String role) { + private static String buildOrderByClauseFromHql(String orderByFragment, PersistentClass associatedClass) { if ( orderByFragment != null ) { if ( orderByFragment.length() == 0 ) { //order by id @@ -1437,7 +1435,7 @@ public abstract class CollectionBinder { if ( collectionTableAnn != null ) { if ( collectionTableAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT || collectionTableAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { - key.setForeignKeyName( "none" ); + key.disableForeignKey(); } else { key.setForeignKeyName( StringHelper.nullIfEmpty( collectionTableAnn.foreignKey().name() ) ); @@ -1469,7 +1467,7 @@ public abstract class CollectionBinder { } if ( foreignKeyValue == ConstraintMode.NO_CONSTRAINT || foreignKeyValue == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { - key.setForeignKeyName( "none" ); + key.disableForeignKey(); } else { key.setForeignKeyName( StringHelper.nullIfEmpty( foreignKeyName ) ); @@ -1482,7 +1480,7 @@ public abstract class CollectionBinder { ); if ( fkOverride != null && ( fkOverride.value() == ConstraintMode.NO_CONSTRAINT || fkOverride.value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) ) { - key.setForeignKeyName( "none" ); + key.disableForeignKey(); } else if ( fkOverride != null ) { key.setForeignKeyName( StringHelper.nullIfEmpty( fkOverride.name() ) ); @@ -1495,14 +1493,14 @@ public abstract class CollectionBinder { && ( onDeleteAnn == null || onDeleteAnn.action() != OnDeleteAction.CASCADE ) ) { // foreign key should be up to @ManyToOne side // @OnDelete generate "on delete cascade" foreign key - key.setForeignKeyName( "none" ); + key.disableForeignKey(); } else { final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class ); if ( joinColumnAnn != null ) { if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT || joinColumnAnn.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { - key.setForeignKeyName( "none" ); + key.disableForeignKey(); } else { key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) ); @@ -1674,7 +1672,7 @@ public abstract class CollectionBinder { // as per 11.1.38 of JPA 2.0 spec, default to primary key if no column is specified by @OrderBy. if ( hqlOrderBy != null ) { collValue.setManyToManyOrdering( - buildOrderByClauseFromHql( hqlOrderBy, collectionEntity, collValue.getRole() ) + buildOrderByClauseFromHql( hqlOrderBy, collectionEntity) ); } @@ -1687,20 +1685,16 @@ public abstract class CollectionBinder { if ( joinTableAnn != null ) { String foreignKeyName = joinTableAnn.inverseForeignKey().name(); String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition(); - ConstraintMode foreignKeyValue = joinTableAnn.inverseForeignKey().value(); if ( joinTableAnn.inverseJoinColumns().length != 0 ) { final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0]; if ( foreignKeyName != null && foreignKeyName.isEmpty() ) { foreignKeyName = joinColumnAnn.foreignKey().name(); foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition(); } - if ( foreignKeyValue != ConstraintMode.NO_CONSTRAINT ) { - foreignKeyValue = joinColumnAnn.foreignKey().value(); - } } if ( joinTableAnn.inverseForeignKey().value() == ConstraintMode.NO_CONSTRAINT || joinTableAnn.inverseForeignKey().value() == ConstraintMode.PROVIDER_DEFAULT && buildingContext.getBuildingOptions().isNoConstraintByDefault() ) { - element.setForeignKeyName( "none" ); + element.disableForeignKey(); } else { element.setForeignKeyName( StringHelper.nullIfEmpty( foreignKeyName ) ); @@ -2089,7 +2083,7 @@ public abstract class CollectionBinder { this.mapKeyManyToManyColumns = mapJoinColumns; } - public void setLocalGenerators(HashMap localGenerators) { + public void setLocalGenerators(Map localGenerators) { this.localGenerators = localGenerators; } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java index 5b472a473d..c84ed9b521 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -31,7 +31,6 @@ import org.hibernate.MappingException; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Columns; import org.hibernate.annotations.Comment; import org.hibernate.annotations.DynamicInsert; import org.hibernate.annotations.DynamicUpdate; @@ -70,8 +69,6 @@ import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.AnnotatedJoinColumn; -import org.hibernate.cfg.InheritanceState; -import org.hibernate.cfg.ObjectNameSource; import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.UniqueConstraintHolder; import org.hibernate.engine.OptimisticLockStyle; @@ -103,7 +100,8 @@ import static org.hibernate.cfg.BinderHelper.toAliasTableMap; * @author Emmanuel Bernard */ public class EntityBinder { - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, EntityBinder.class.getName()); + + private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, EntityBinder.class.getName() ); private static final String NATURAL_ID_CACHE_SUFFIX = "##NaturalId"; private MetadataBuildingContext context; @@ -125,10 +123,9 @@ public class EntityBinder { private String where; // todo : we should defer to InFlightMetadataCollector.EntityTableXref for secondary table tracking; // atm we use both from here; HBM binding solely uses InFlightMetadataCollector.EntityTableXref - private java.util.Map secondaryTables = new HashMap<>(); - private java.util.Map secondaryTableJoins = new HashMap<>(); - private List filters = new ArrayList<>(); - private InheritanceState inheritanceState; + private final java.util.Map secondaryTables = new HashMap<>(); + private final java.util.Map secondaryTableJoins = new HashMap<>(); + private final List filters = new ArrayList<>(); private boolean ignoreIdAnnotations; private AccessType propertyAccessType = AccessType.DEFAULT; private boolean wrapIdsInEmbeddedComponents; @@ -151,14 +148,13 @@ public class EntityBinder { } public EntityBinder( - Entity ejb3Ann, XClass annotatedClass, PersistentClass persistentClass, MetadataBuildingContext context) { this.context = context; this.persistentClass = persistentClass; this.annotatedClass = annotatedClass; - bindEjb3Annotation( ejb3Ann ); + bindEntityAnnotation( annotatedClass.getAnnotation( Entity.class ) ); bindHibernateAnnotation(); } @@ -170,14 +166,10 @@ public class EntityBinder { * * @return {@code true} if a property by that given name does already exist in the super hierarchy. */ - @SuppressWarnings("SimplifiableIfStatement") public boolean isPropertyDefinedInSuperHierarchy(String name) { // Yes, yes... persistentClass can be null because EntityBinder can be used // to bind components as well, of course... - if ( persistentClass == null ) { - return false; - } - return persistentClass.isPropertyDefinedInSuperHierarchy( name ); + return persistentClass != null && persistentClass.isPropertyDefinedInSuperHierarchy( name ); } @SuppressWarnings("SimplifiableConditionalExpression") @@ -218,14 +210,13 @@ public class EntityBinder { } } - private void bindEjb3Annotation(Entity ejb3Ann) { - if ( ejb3Ann == null ) throw new AssertionFailure( "@Entity should always be not null" ); - if ( BinderHelper.isEmptyAnnotationValue( ejb3Ann.name() ) ) { - name = StringHelper.unqualify( annotatedClass.getName() ); - } - else { - name = ejb3Ann.name(); + private void bindEntityAnnotation(Entity ejb3Ann) { + if ( ejb3Ann == null ) { + throw new AssertionFailure( "@Entity should never be missing" ); } + name = BinderHelper.isEmptyAnnotationValue( ejb3Ann.name() ) + ? StringHelper.unqualify(annotatedClass.getName()) + : ejb3Ann.name(); } public boolean isRootEntity() { @@ -262,11 +253,7 @@ public class EntityBinder { if ( persistentClass instanceof RootClass ) { RootClass rootClass = (RootClass) persistentClass; - boolean mutable = true; - //priority on @Immutable, then @Entity.mutable() - if ( annotatedClass.isAnnotationPresent( Immutable.class ) ) { - mutable = false; - } + boolean mutable = !annotatedClass.isAnnotationPresent( Immutable.class ); rootClass.setMutable( mutable ); rootClass.setExplicitPolymorphism( isExplicitPolymorphism( polymorphismType ) ); @@ -307,6 +294,7 @@ public class EntityBinder { //set persister if needed Persister persisterAnn = annotatedClass.getAnnotation( Persister.class ); if ( persisterAnn != null ) { + //TODO: throw an error if the class doesn't inherit EntityPersister Class persister = (Class) persisterAnn.impl(); persistentClass.setEntityPersisterClass( persister ); } @@ -477,7 +465,6 @@ public class EntityBinder { } } - @SuppressWarnings({ "unchecked" }) public void setProxy(Proxy proxy) { if ( proxy != null ) { lazy = proxy.lazy(); @@ -514,6 +501,7 @@ public class EntityBinder { XClass clazzToProcess, SharedCacheMode sharedCacheMode, MetadataBuildingContext context) { + final Cache explicitCacheAnn = clazzToProcess.getAnnotation( Cache.class ); final Cacheable explicitCacheableAnn = clazzToProcess.getAnnotation( Cacheable.class ); @@ -678,26 +666,6 @@ public class EntityBinder { ); } - private static class EntityTableObjectNameSource implements ObjectNameSource { - private final String explicitName; - private final String logicalName; - - private EntityTableObjectNameSource(String explicitName, String entityName) { - this.explicitName = explicitName; - this.logicalName = StringHelper.isNotEmpty( explicitName ) - ? explicitName - : StringHelper.unqualify( entityName ); - } - - public String getExplicitName() { - return explicitName; - } - - public String getLogicalName() { - return logicalName; - } - } - private static class EntityTableNamingStrategyHelper implements NamingStrategyHelper { private final String className; private final String entityName; @@ -761,7 +729,7 @@ public class EntityBinder { } public void bindTableForDiscriminatedSubclass(InFlightMetadataCollector.EntityTableXref superTableXref) { - if ( !SingleTableSubclass.class.isInstance( persistentClass ) ) { + if ( !(persistentClass instanceof SingleTableSubclass) ) { throw new AssertionFailure( "Was expecting a discriminated subclass [" + SingleTableSubclass.class.getName() + "] but found [" + persistentClass.getClass().getName() + "] for entity [" + @@ -951,7 +919,7 @@ public class EntityBinder { final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); if ( jpaSecondaryTable.foreignKey().value() == ConstraintMode.NO_CONSTRAINT || jpaSecondaryTable.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { - ( (SimpleValue) join.getKey() ).setForeignKeyName( "none" ); + ( (SimpleValue) join.getKey() ).disableForeignKey(); } else { ( (SimpleValue) join.getKey() ).setForeignKeyName( StringHelper.nullIfEmpty( jpaSecondaryTable.foreignKey().name() ) ); @@ -1021,33 +989,6 @@ public class EntityBinder { return addJoin( null, joinTable, holder, noDelayInPkColumnCreation ); } - private static class SecondaryTableNamingStrategyHelper implements NamingStrategyHelper { - @Override - public Identifier determineImplicitName(MetadataBuildingContext buildingContext) { - // should maybe throw an exception here - return null; - } - - @Override - public Identifier handleExplicitName(String explicitName, MetadataBuildingContext buildingContext) { - return buildingContext.getMetadataCollector() - .getDatabase() - .getJdbcEnvironment() - .getIdentifierHelper() - .toIdentifier( explicitName ); - } - - @Override - public Identifier toPhysicalName(Identifier logicalName, MetadataBuildingContext buildingContext) { - return buildingContext.getBuildingOptions().getPhysicalNamingStrategy().toPhysicalTableName( - logicalName, - buildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment() - ); - } - } - - private static SecondaryTableNamingStrategyHelper SEC_TBL_NS_HELPER = new SecondaryTableNamingStrategyHelper(); - private Join addJoin( SecondaryTable secondaryTable, JoinTable joinTable, @@ -1185,10 +1126,6 @@ public class EntityBinder { filters.add(filter); } - public void setInheritanceState(InheritanceState inheritanceState) { - this.inheritanceState = inheritanceState; - } - public boolean isIgnoreIdAnnotations() { return ignoreIdAnnotations; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java index d919143af5..51f71c08e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java @@ -348,7 +348,7 @@ public class MapBinder extends CollectionBinder { if ( foreignKey != null ) { if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT || foreignKey.value() == ConstraintMode.PROVIDER_DEFAULT && getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) { - element.setForeignKeyName( "none" ); + element.disableForeignKey(); } else { element.setForeignKeyName( StringHelper.nullIfEmpty( foreignKey.name() ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java index 40227945c7..ca822da63a 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java @@ -48,8 +48,8 @@ public class ForeignKey extends Constraint { @Override public void setName(String name) { super.setName( name ); - // the FK name "none" is a magic value in the hbm.xml binding that indicated to - // not create a FK. + // the FK name "none" was a magic value in the hbm.xml + // mapping language that indicated to not create a FK if ( "none".equals( name ) ) { disableCreation(); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java b/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java index 65aa0cee2a..410172fcc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java @@ -50,7 +50,7 @@ public class ManyToOne extends ToOne { // Ensure properties are sorted before we create a foreign key sortProperties(); // the case of a foreign key to something other than the pk is handled in createPropertyRefConstraints - if ( referencedPropertyName==null && !hasFormula() ) { + if ( isForeignKeyEnabled() && referencedPropertyName==null && !hasFormula() ) { createForeignKeyOfEntity( ( (EntityType) getType() ).getAssociatedEntityName() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java b/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java index 72618f1280..6dcc708dcd 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java @@ -82,7 +82,7 @@ public class OneToOne extends ToOne { public void createForeignKey() throws MappingException { // Ensure properties are sorted before we create a foreign key sortProperties(); - if ( constrained && referencedPropertyName==null) { + if ( isForeignKeyEnabled() && constrained && referencedPropertyName==null) { //TODO: handle the case of a foreign key to something other than the pk createForeignKeyOfEntity( ( (EntityType) getType() ).getAssociatedEntityName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java index 8e84cc842c..6d72603d01 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java @@ -296,7 +296,7 @@ public class RootClass extends PersistentClass implements TableOwner { if ( getIdentifier() instanceof Component ) { Component id = (Component) getIdentifier(); if ( !id.isDynamic() ) { - final Class idClass = id.getComponentClass(); + final Class idClass = id.getComponentClass(); if ( idClass != null ) { final String idComponentClassName = idClass.getName(); if ( !ReflectHelper.overridesEquals( idClass ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index 5d6d732072..18d279269d 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -93,6 +93,7 @@ public abstract class SimpleValue implements KeyValue { private String foreignKeyDefinition; private boolean alternateUniqueKey; private boolean cascadeDeleteEnabled; + private boolean foreignKeyEnabled = true; private ConverterDescriptor attributeConverterDescriptor; private Type type; @@ -291,7 +292,7 @@ public abstract class SimpleValue implements KeyValue { @Override public void createForeignKeyOfEntity(String entityName) { - if ( !hasFormula() && !"none".equals( getForeignKeyName() ) ) { + if ( isConstrained() ) { table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName, getForeignKeyDefinition() ) .setCascadeDeleteEnabled(cascadeDeleteEnabled); } @@ -545,11 +546,24 @@ public abstract class SimpleValue implements KeyValue { } public void setForeignKeyName(String foreignKeyName) { + // the FK name "none" was a magic value in the hbm.xml + // mapping language that indicated to not create a FK + if ( "none".equals( foreignKeyName ) ) { + foreignKeyEnabled = false; + } this.foreignKeyName = foreignKeyName; } + public boolean isForeignKeyEnabled() { + return foreignKeyEnabled; + } + + public void disableForeignKey() { + this.foreignKeyEnabled = false; + } + public boolean isConstrained() { - return !"none".equals( foreignKeyName ) && !hasFormula(); + return isForeignKeyEnabled() && !hasFormula(); } public String getForeignKeyDefinition() { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/StandardAnyTypeDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/StandardAnyTypeDefinition.java index a5be17a432..2f4bf6eec6 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/StandardAnyTypeDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/StandardAnyTypeDefinition.java @@ -32,7 +32,7 @@ public class StandardAnyTypeDefinition implements AnyMappingDefinition { private static List interpretDiscriminatorMappings(AnyType anyType) { final Type discriminatorType = anyType.getDiscriminatorType(); - if ( ! MetaType.class.isInstance( discriminatorType ) ) { + if ( !(discriminatorType instanceof MetaType) ) { return Collections.emptyList(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java index 900c29f01f..1e16eed1b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java @@ -22,7 +22,7 @@ import jakarta.persistence.TemporalType; /** * Defines the aspects of query execution and parameter binding that apply to all * forms of querying - HQL, {@linkplain jakarta.persistence.criteria.CriteriaBuilder - * criteria queries} and {@link org.hibernate.procedure.ProcedureCall stored + * criteria queries}, and {@link org.hibernate.procedure.ProcedureCall stored * procedure calls}. * * @author Steve Ebersole