From 218ace291f8ee54cae561864f8e7cec3254928b3 Mon Sep 17 00:00:00 2001 From: Gavin Date: Sun, 25 Dec 2022 18:15:56 +0100 Subject: [PATCH] HHH-15934 correctly handle @Basic(optional=false) previously it had no effect --- .../boot/model/internal/AnnotationBinder.java | 131 +++++++++--------- .../boot/model/internal/BasicValueBinder.java | 41 ++++-- .../boot/model/internal/CollectionBinder.java | 1 + .../boot/model/internal/ListBinder.java | 1 + .../boot/model/internal/PropertyBinder.java | 97 +++++++------ .../boot/model/internal/ToOneBinder.java | 3 +- .../source/internal/hbm/ModelBinder.java | 80 ++++++----- .../ast/internal/LoaderSelectBuilder.java | 49 ++----- .../internal/NoCallbackExecutionContext.java | 4 +- .../java/org/hibernate/mapping/Property.java | 90 ++++++------ .../entity/AbstractEntityPersister.java | 12 +- .../sql/ast/tree/select/SelectStatement.java | 2 - .../various/OneOneGeneratedValueTest.java | 2 - .../test/mapping/naturalid/nullable/B.java | 1 + 14 files changed, 263 insertions(+), 251 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java index d07f5db0a2..7dac644e30 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java @@ -18,6 +18,41 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinColumns; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.MapsId; +import jakarta.persistence.NamedNativeQueries; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.NamedStoredProcedureQueries; +import jakarta.persistence.NamedStoredProcedureQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.SequenceGenerators; +import jakarta.persistence.SqlResultSetMapping; +import jakarta.persistence.SqlResultSetMappings; +import jakarta.persistence.TableGenerator; +import jakarta.persistence.TableGenerators; +import jakarta.persistence.Version; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; @@ -112,42 +147,6 @@ import org.hibernate.usertype.UserType; import org.hibernate.usertype.internal.OffsetDateTimeCompositeUserType; import org.hibernate.usertype.internal.ZonedDateTimeCompositeUserType; -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.Embeddable; -import jakarta.persistence.Embedded; -import jakarta.persistence.EmbeddedId; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Inheritance; -import jakarta.persistence.InheritanceType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.JoinColumns; -import jakarta.persistence.JoinTable; -import jakarta.persistence.ManyToMany; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.MapsId; -import jakarta.persistence.NamedNativeQueries; -import jakarta.persistence.NamedNativeQuery; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.NamedStoredProcedureQueries; -import jakarta.persistence.NamedStoredProcedureQuery; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.SequenceGenerators; -import jakarta.persistence.SqlResultSetMapping; -import jakarta.persistence.SqlResultSetMappings; -import jakarta.persistence.TableGenerator; -import jakarta.persistence.TableGenerators; -import jakarta.persistence.Version; - import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.getPath; @@ -1252,7 +1251,6 @@ public final class AnnotationBinder { isIdentifierMapper, context, inheritanceStatePerClass, - property, columnsBuilder.getColumns(), propertyBinder ); @@ -1349,7 +1347,6 @@ public final class AnnotationBinder { boolean isIdentifierMapper, MetadataBuildingContext context, Map inheritanceStatePerClass, - XProperty annotatedProperty, AnnotatedColumns columns, PropertyBinder propertyBinder) { checkVersionProperty( propertyHolder, isIdentifierMapper ); @@ -1565,32 +1562,12 @@ public final class AnnotationBinder { AnnotatedColumns columns, PropertyBinder propertyBinder, boolean isOverridden) { - //provide the basic property mapping - final boolean optional; - final boolean lazy; - if ( property.isAnnotationPresent( Basic.class ) ) { - final Basic basic = property.getAnnotation( Basic.class ); - optional = basic.optional(); - lazy = basic.fetch() == FetchType.LAZY; - } - else { - optional = true; - lazy = false; + + if ( shouldForceNotNull( nullability, propertyBinder, isOptional( property ) ) ) { + forceColumnsNotNull( propertyHolder, inferredData, columns, propertyBinder ); } - //implicit type will check basic types and Serializable classes - if ( propertyBinder.isId() || !optional && nullability != Nullability.FORCED_NULL ) { - //force columns to not null - for ( AnnotatedColumn column : columns.getColumns() ) { - if ( propertyBinder.isId() && column.isFormula() ) { - throw new CannotForceNonNullableException( "Identifier property '" - + getPath( propertyHolder, inferredData ) + "' cannot map to a '@Formula'" ); - } - column.forceNotNull(); - } - } - - propertyBinder.setLazy( lazy ); + propertyBinder.setLazy( BasicValueBinder.isLazy( property ) ); propertyBinder.setColumns( columns ); if ( isOverridden ) { final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId( @@ -1605,6 +1582,36 @@ public final class AnnotationBinder { propertyBinder.makePropertyValueAndBind(); } + private static void forceColumnsNotNull( + PropertyHolder propertyHolder, + PropertyData inferredData, + AnnotatedColumns columns, + PropertyBinder propertyBinder) { + for ( AnnotatedColumn column : columns.getColumns() ) { + if ( propertyBinder.isId() && column.isFormula() ) { + throw new CannotForceNonNullableException( "Identifier property '" + + getPath( propertyHolder, inferredData ) + "' cannot map to a '@Formula'" ); + } + column.forceNotNull(); + } + } + + private static boolean shouldForceNotNull(Nullability nullability, PropertyBinder propertyBinder, boolean optional) { + return propertyBinder.isId() + || !optional && nullability != Nullability.FORCED_NULL; + } + + static boolean isOptional(XProperty property) { + if ( property.isAnnotationPresent( Basic.class ) ) { + final Basic basic = property.getAnnotation( Basic.class ); + return basic.optional(); + } + else { + return true; + } + } + + private static PropertyBinder createCompositeBinder( PropertyHolder propertyHolder, PropertyData inferredData, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java index c5510e3e45..1b5b87eb9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java @@ -14,6 +14,8 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Function; +import jakarta.persistence.Basic; +import jakarta.persistence.FetchType; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; @@ -105,6 +107,26 @@ public class BasicValueBinder implements JdbcTypeIndicators { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicValueBinder.class.getName() ); + static boolean isOptional(XProperty property) { + if ( property.isAnnotationPresent( Basic.class ) ) { + final Basic basic = property.getAnnotation( Basic.class ); + return basic.optional(); + } + else { + return property.isArray() || !property.getClassOrElementClass().isPrimitive(); + } + } + + static boolean isLazy(XProperty property) { + if ( property.isAnnotationPresent( Basic.class ) ) { + final Basic basic = property.getAnnotation( Basic.class ); + return basic.fetch() == FetchType.LAZY; + } + else { + return false; + } + } + public enum Kind { ATTRIBUTE( ValueMappingAccess.INSTANCE ), ANY_DISCRIMINATOR( AnyDiscriminatorMappingAccess.INSTANCE ), @@ -143,7 +165,6 @@ public class BasicValueBinder implements JdbcTypeIndicators { private ConverterDescriptor converterDescriptor; - private boolean isVersion; private boolean isNationalized; private boolean isLob; private EnumType enumType; @@ -266,7 +287,6 @@ public class BasicValueBinder implements JdbcTypeIndicators { // in-flight handling public void setVersion(boolean isVersion) { - this.isVersion = isVersion; if ( isVersion && basicValue != null ) { basicValue.makeVersion(); } @@ -511,7 +531,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; // todo (6.0) - handle generator - final String generator = collectionIdAnn.generator(); +// final String generator = collectionIdAnn.generator(); } private ManagedBeanRegistry getManagedBeanRegistry() { @@ -523,17 +543,9 @@ public class BasicValueBinder implements JdbcTypeIndicators { private void prepareMapKey( XProperty mapAttribute, XClass modelPropertyTypeXClass) { - final XClass mapKeyClass; - if ( modelPropertyTypeXClass == null ) { - mapKeyClass = mapAttribute.getMapKey(); - } - else { - mapKeyClass = modelPropertyTypeXClass; - } + final XClass mapKeyClass = modelPropertyTypeXClass == null ? mapAttribute.getMapKey() : modelPropertyTypeXClass; final java.lang.reflect.Type javaType = resolveJavaType( mapKeyClass ); - final Class javaTypeClass = ReflectHelper.getClass( javaType ); - - implicitJavaTypeAccess = (typeConfiguration) -> javaType; + implicitJavaTypeAccess = typeConfiguration -> javaType; final MapKeyEnumerated mapKeyEnumeratedAnn = mapAttribute.getAnnotation( MapKeyEnumerated.class ); if ( mapKeyEnumeratedAnn != null ) { @@ -570,8 +582,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { if ( javaTypeAnn != null ) { final Class> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() ); if ( jdbcTypeImpl != null ) { - final ManagedBean jdbcTypeBean = getManagedBeanRegistry().getBean( jdbcTypeImpl ); - return jdbcTypeBean.getBeanInstance(); + return getManagedBeanRegistry().getBean( jdbcTypeImpl ).getBeanInstance(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java index 03c1ab7a59..dc033fe0da 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java @@ -1629,6 +1629,7 @@ public abstract class CollectionBinder { + '_' + foreignJoinColumns.getColumns().get(0).getLogicalColumnName() + "Backref"; backref.setName( backrefName ); + backref.setOptional( true ); backref.setUpdateable( false); backref.setSelectable( false ); backref.setCollectionRole( collection.getRole() ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java index eeaf6b7d3b..4e63684575 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java @@ -104,6 +104,7 @@ public class ListBinder extends CollectionBinder { final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName ); final IndexBackref backref = new IndexBackref(); backref.setName( '_' + propertyName + "IndexBackref" ); + backref.setOptional( true ); backref.setUpdateable( false ); backref.setSelectable( false ); backref.setCollectionRole( collection.getRole() ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java index acca551920..3022d0cc6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java @@ -55,6 +55,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Lob; import jakarta.persistence.Version; +import static org.hibernate.boot.model.internal.BasicValueBinder.isOptional; import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotation; import static org.hibernate.internal.util.StringHelper.qualify; @@ -324,19 +325,15 @@ public class PropertyBinder { } private Class resolveCustomInstantiator(XProperty property, XClass embeddableClass) { - final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = - property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); - if ( propertyAnnotation != null ) { - return propertyAnnotation.value(); + if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { + return property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value(); } - - final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = - embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); - if ( classAnnotation != null ) { - return classAnnotation.value(); + else if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { + return embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value(); + } + else { + return null; } - - return null; } //used when the value is provided and the binding is done elsewhere @@ -351,48 +348,58 @@ public class PropertyBinder { property.setCascade( cascade ); property.setPropertyAccessorName( accessType.getType() ); property.setReturnedClassName( returnedClassName ); - - if ( this.property != null ) { - if ( entityBinder != null ) { - handleNaturalId( property ); - property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.property ) ); - } - // HHH-4635 -- needed for dialect-specific property ordering - property.setLob( this.property.isAnnotationPresent( Lob.class ) ); - } - property.setPropertyAccessStrategy( propertyAccessStrategy ); - - handleImmutable( property ); - + handleValueGeneration( property ); + handleNaturalId( property ); + handleLob( property ); + handleMutability( property ); + handleOptional( property ); inferOptimisticLocking( property ); - - property.setInsertable( insertable ); - property.setUpdateable( updatable ); - LOG.tracev( "Cascading {0} with {1}", name, cascade ); - return property; } - private void handleImmutable(Property property) { + private void handleValueGeneration(Property property) { + if ( this.property!=null ) { + property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.property ) ); + } + } + + private void handleLob(Property property) { + if ( this.property != null ) { + // HHH-4635 -- needed for dialect-specific property ordering + property.setLob( this.property.isAnnotationPresent( Lob.class ) ); + } + } + + private void handleMutability(Property property) { if ( this.property != null && this.property.isAnnotationPresent( Immutable.class ) ) { updatable = false; } + property.setInsertable( insertable ); + property.setUpdateable( updatable ); + } + + private void handleOptional(Property property) { + if ( this.property != null ) { + property.setOptional( !isId && isOptional( this.property ) ); + } } private void handleNaturalId(Property property) { - final NaturalId naturalId = this.property.getAnnotation(NaturalId.class); - if ( naturalId != null ) { - if ( !entityBinder.isRootEntity() ) { - throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) - + "' belongs to an entity subclass and may not be annotated '@NaturalId'" + - " (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" ); + if ( this.property != null && entityBinder != null ) { + final NaturalId naturalId = this.property.getAnnotation( NaturalId.class ); + if ( naturalId != null ) { + if ( !entityBinder.isRootEntity() ) { + throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) + + "' belongs to an entity subclass and may not be annotated '@NaturalId'" + + " (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" ); + } + if ( !naturalId.mutable() ) { + updatable = false; + } + property.setNaturalIdentifier( true ); } - if ( !naturalId.mutable() ) { - updatable = false; - } - property.setNaturalIdentifier( true ); } } @@ -401,8 +408,8 @@ public class PropertyBinder { if ( value instanceof Collection ) { property.setOptimisticLocked( ((Collection) value).isOptimisticLocked() ); } - else if ( this.property != null && this.property.isAnnotationPresent(OptimisticLock.class) ) { - final OptimisticLock optimisticLock = this.property.getAnnotation(OptimisticLock.class); + else if ( this.property != null && this.property.isAnnotationPresent( OptimisticLock.class ) ) { + final OptimisticLock optimisticLock = this.property.getAnnotation( OptimisticLock.class ); validateOptimisticLock( optimisticLock ); property.setOptimisticLocked( !optimisticLock.excluded() ); } @@ -413,15 +420,15 @@ public class PropertyBinder { private void validateOptimisticLock(OptimisticLock optimisticLock) { if ( optimisticLock.excluded() ) { - if ( property.isAnnotationPresent(Version.class) ) { + if ( property.isAnnotationPresent( Version.class ) ) { throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" ); } - if ( property.isAnnotationPresent(Id.class) ) { + if ( property.isAnnotationPresent( Id.class ) ) { throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" ); } - if ( property.isAnnotationPresent(EmbeddedId.class) ) { + if ( property.isAnnotationPresent( EmbeddedId.class ) ) { throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java index 8846ce4042..5605bb2d95 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java @@ -94,11 +94,10 @@ public class ToOneBinder { joinColumn.setExplicitTableName( join.getTable().getName() ); } } - final boolean mandatory = isMandatory( manyToOne.optional(), property, notFoundAction ); bindManyToOne( getCascadeStrategy( manyToOne.cascade(), hibernateCascade, false, forcePersist ), joinColumns, - !mandatory, + !isMandatory( manyToOne.optional(), property, notFoundAction ), notFoundAction, onDelete == null ? null : onDelete.action(), getTargetEntity( inferredData, context ), 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 7aa2b55bbc..d5b9137624 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 @@ -1090,6 +1090,7 @@ public class ModelBinder { (PluralAttributeSource) attributeSource, entityDescriptor ); + attribute.setOptional( true ); entityDescriptor.addProperty( attribute ); } else { @@ -1116,9 +1117,7 @@ public class ModelBinder { entityDescriptor.getClassName() ); - if ( secondaryTableJoin != null ) { - attribute.setOptional( secondaryTableJoin.isOptional() ); - } + attribute.setOptional( isOptional( secondaryTableJoin, attribute ) ); attributeContainer.addProperty( attribute ); @@ -1151,9 +1150,7 @@ public class ModelBinder { entityDescriptor.getClassName() ); - if ( secondaryTableJoin != null ) { - attribute.setOptional( secondaryTableJoin.isOptional() ); - } + attribute.setOptional( isOptional( secondaryTableJoin, attribute ) ); attributeContainer.addProperty( attribute ); @@ -1186,9 +1183,7 @@ public class ModelBinder { entityDescriptor.getClassName() ); - if ( secondaryTableJoin != null ) { - attribute.setOptional( secondaryTableJoin.isOptional() ); - } + attribute.setOptional( isOptional( secondaryTableJoin, attribute ) ); attributeContainer.addProperty( attribute ); @@ -1208,6 +1203,9 @@ public class ModelBinder { new OneToOne( mappingDocument, table, entityDescriptor ), entityDescriptor.getClassName() ); + + attribute.setOptional( attribute.getValue().isNullable() ); + entityDescriptor.addProperty( attribute ); handleNaturalIdBinding( @@ -1243,9 +1241,7 @@ public class ModelBinder { entityDescriptor.getEntityName() ); - if ( secondaryTableJoin != null ) { - attribute.setOptional( secondaryTableJoin.isOptional() ); - } + attribute.setOptional( isOptional( secondaryTableJoin, attribute ) ); attributeContainer.addProperty( attribute ); @@ -1260,6 +1256,11 @@ public class ModelBinder { } } + private static boolean isOptional(Join secondaryTableJoin, Property attribute) { + return secondaryTableJoin != null && secondaryTableJoin.isOptional() + || attribute.getValue().isNullable(); + } + private void handleNaturalIdBinding( MappingDocument mappingDocument, PersistentClass entityBinding, @@ -2785,6 +2786,8 @@ public class ModelBinder { ); } + attribute.setOptional( attribute.getValue().isNullable() ); + component.addProperty( attribute ); } } @@ -3286,19 +3289,20 @@ public class ModelBinder { // for non-inverse one-to-many, with a not-null fk, add a backref! final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName(); final PersistentClass referenced = getReferencedEntityBinding( entityName ); - final Backref prop = new Backref(); - prop.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" ); - prop.setUpdateable( false ); - prop.setSelectable( false ); - prop.setCollectionRole( collectionBinding.getRole() ); - prop.setEntityName( collectionBinding.getOwner().getEntityName() ); - prop.setValue( collectionBinding.getKey() ); - referenced.addProperty( prop ); + final Backref backref = new Backref(); + backref.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" ); + backref.setOptional( true ); + backref.setUpdateable( false ); + backref.setSelectable( false ); + backref.setCollectionRole( collectionBinding.getRole() ); + backref.setEntityName( collectionBinding.getOwner().getEntityName() ); + backref.setValue( collectionBinding.getKey() ); + referenced.addProperty( backref ); if ( log.isDebugEnabled() ) { log.debugf( "Added virtual backref property [%s] : %s", - prop.getName(), + backref.getName(), pluralAttributeSource.getAttributeRole().getFullPath() ); } @@ -3748,14 +3752,15 @@ public class ModelBinder { && !indexIsFormula ) { final String entityName = ( (OneToMany) getCollectionBinding().getElement() ).getReferencedEntityName(); final PersistentClass referenced = getMappingDocument().getMetadataCollector().getEntityBinding( entityName ); - final IndexBackref ib = new IndexBackref(); - ib.setName( '_' + getCollectionBinding().getOwnerEntityName() + "." + getPluralAttributeSource().getName() + "IndexBackref" ); - ib.setUpdateable( false ); - ib.setSelectable( false ); - ib.setCollectionRole( getCollectionBinding().getRole() ); - ib.setEntityName( getCollectionBinding().getOwner().getEntityName() ); - ib.setValue( getCollectionBinding().getIndex() ); - referenced.addProperty( ib ); + final IndexBackref backref = new IndexBackref(); + backref.setName( '_' + getCollectionBinding().getOwnerEntityName() + "." + getPluralAttributeSource().getName() + "IndexBackref" ); + backref.setOptional( true ); + backref.setUpdateable( false ); + backref.setSelectable( false ); + backref.setCollectionRole( getCollectionBinding().getRole() ); + backref.setEntityName( getCollectionBinding().getOwner().getEntityName() ); + backref.setValue( getCollectionBinding().getIndex() ); + referenced.addProperty( backref ); } } } @@ -3826,14 +3831,15 @@ public class ModelBinder { && !collectionBinding.isInverse() ) { final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName(); final PersistentClass referenced = mappingDocument.getMetadataCollector().getEntityBinding( entityName ); - final IndexBackref ib = new IndexBackref(); - ib.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "IndexBackref" ); - ib.setUpdateable( false ); - ib.setSelectable( false ); - ib.setCollectionRole( collectionBinding.getRole() ); - ib.setEntityName( collectionBinding.getOwner().getEntityName() ); - ib.setValue( collectionBinding.getIndex() ); - referenced.addProperty( ib ); + final IndexBackref backref = new IndexBackref(); + backref.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "IndexBackref" ); + backref.setOptional( true ); + backref.setUpdateable( false ); + backref.setSelectable( false ); + backref.setCollectionRole( collectionBinding.getRole() ); + backref.setEntityName( collectionBinding.getOwner().getEntityName() ); + backref.setValue( collectionBinding.getIndex() ); + referenced.addProperty( backref ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java index c7ae496f38..1cb6385f68 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java @@ -8,8 +8,6 @@ package org.hibernate.loader.ast.internal; import java.util.AbstractMap; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -31,7 +29,6 @@ import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.loader.ast.spi.Loadable; import org.hibernate.loader.ast.spi.Loader; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; @@ -56,7 +53,6 @@ import org.hibernate.sql.ast.spi.SimpleFromClauseAccessImpl; import org.hibernate.sql.ast.spi.SqlAliasBaseManager; import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationState; -import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; @@ -89,8 +85,8 @@ import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; import org.jboss.logging.Logger; +import static java.util.Collections.singletonList; import static org.hibernate.query.results.ResultsHelper.attributeName; -import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey; /** * Builder for SQL AST trees used by {@link Loader} implementations. @@ -128,7 +124,7 @@ public class LoaderSelectBuilder { sessionFactory, loadable, partsToSelect, - Collections.singletonList( restrictedPart ), + singletonList( restrictedPart ), cachedDomainResult, numberOfKeysToLoad, loadQueryInfluencers, @@ -220,7 +216,7 @@ public class LoaderSelectBuilder { public static SelectStatement createSubSelectFetchSelect( PluralAttributeMapping attributeMapping, SubselectFetch subselect, - DomainResult cachedDomainResult, + DomainResult cachedDomainResult, LoadQueryInfluencers loadQueryInfluencers, LockOptions lockOptions, Consumer jdbcParameterConsumer, @@ -244,7 +240,7 @@ public class LoaderSelectBuilder { private final Loadable loadable; private final List partsToSelect; private final List restrictedParts; - private final DomainResult cachedDomainResult; + private final DomainResult cachedDomainResult; private final int numberOfKeysToLoad; private final boolean forceIdentifierSelection; private final LoadQueryInfluencers loadQueryInfluencers; @@ -262,7 +258,7 @@ public class LoaderSelectBuilder { Loadable loadable, List partsToSelect, List restrictedParts, - DomainResult cachedDomainResult, + DomainResult cachedDomainResult, int numberOfKeysToLoad, LoadQueryInfluencers loadQueryInfluencers, LockOptions lockOptions, @@ -287,7 +283,7 @@ public class LoaderSelectBuilder { Loadable loadable, List partsToSelect, List restrictedParts, - DomainResult cachedDomainResult, + DomainResult cachedDomainResult, int numberOfKeysToLoad, LoadQueryInfluencers loadQueryInfluencers, LockOptions lockOptions, @@ -312,7 +308,7 @@ public class LoaderSelectBuilder { Loadable loadable, List partsToSelect, ModelPart restrictedPart, - DomainResult cachedDomainResult, + DomainResult cachedDomainResult, int numberOfKeysToLoad, LoadQueryInfluencers loadQueryInfluencers, LockOptions lockOptions, @@ -321,7 +317,7 @@ public class LoaderSelectBuilder { creationContext, loadable, partsToSelect, - Arrays.asList( restrictedPart ), + singletonList( restrictedPart ), cachedDomainResult, numberOfKeysToLoad, loadQueryInfluencers, @@ -356,7 +352,7 @@ public class LoaderSelectBuilder { final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph(); if ( effectiveEntityGraph != null ) { final GraphSemantic graphSemantic = effectiveEntityGraph.getSemantic(); - final RootGraphImplementor rootGraphImplementor = effectiveEntityGraph.getGraph(); + final RootGraphImplementor rootGraphImplementor = effectiveEntityGraph.getGraph(); if ( graphSemantic != null && rootGraphImplementor != null ) { return new StandardEntityGraphTraversalStateImpl( graphSemantic, rootGraphImplementor ); } @@ -458,7 +454,7 @@ public class LoaderSelectBuilder { } //noinspection unchecked - domainResults = Collections.singletonList( domainResult ); + domainResults = singletonList( domainResult ); } for ( ModelPart restrictedPart : restrictedParts ) { @@ -655,11 +651,7 @@ public class LoaderSelectBuilder { } final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() ); - final BiConsumer processor = createFetchableBiConsumer( - fetchParent, - creationState, - fetches - ); + final BiConsumer processor = createFetchableBiConsumer( fetchParent, creationState, fetches ); final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); if ( fetchParent.getNavigablePath().getParent() != null ) { @@ -759,7 +751,7 @@ public class LoaderSelectBuilder { else if ( loadQueryInfluencers.getEnabledCascadingFetchProfile() != null ) { final CascadeStyle cascadeStyle = fetchable.asAttributeMapping().getAttributeMetadata() .getCascadeStyle(); - final CascadingAction cascadingAction = loadQueryInfluencers.getEnabledCascadingFetchProfile() + final CascadingAction cascadingAction = loadQueryInfluencers.getEnabledCascadingFetchProfile() .getCascadingAction(); if ( cascadeStyle == null || cascadeStyle.doCascade( cascadingAction ) ) { fetchTiming = FetchTiming.IMMEDIATE; @@ -853,7 +845,6 @@ public class LoaderSelectBuilder { creationState ); applyOrdering( - querySpec, fetchablePath, pluralAttributeMapping, creationState @@ -901,7 +892,6 @@ public class LoaderSelectBuilder { } private void applyOrdering( - QuerySpec ast, NavigablePath navigablePath, PluralAttributeMapping pluralAttributeMapping, LoaderSqlAstCreationState sqlAstCreationState) { @@ -988,7 +978,7 @@ public class LoaderSelectBuilder { return new SelectStatement( rootQuerySpec, - List.of( + singletonList( new CollectionDomainResult( rootNavigablePath, attributeMapping, @@ -1006,9 +996,6 @@ public class LoaderSelectBuilder { TableGroup rootTableGroup, SubselectFetch subselect, LoaderSqlAstCreationState sqlAstCreationState) { - final SqlAstCreationContext sqlAstCreationContext = sqlAstCreationState.getCreationContext(); - final SessionFactoryImplementor sessionFactory = sqlAstCreationContext.getSessionFactory(); - assert loadable instanceof PluralAttributeMapping; final PluralAttributeMapping attributeMapping = (PluralAttributeMapping) loadable; @@ -1053,11 +1040,8 @@ public class LoaderSelectBuilder { fkExpression, generateSubSelect( attributeMapping, - rootTableGroup, subselect, - jdbcTypeCount, - sqlAstCreationState, - sessionFactory + sqlAstCreationState ), false ) @@ -1066,11 +1050,8 @@ public class LoaderSelectBuilder { private QueryPart generateSubSelect( PluralAttributeMapping attributeMapping, - TableGroup rootTableGroup, SubselectFetch subselect, - int jdbcTypeCount, - LoaderSqlAstCreationState creationState, - SessionFactoryImplementor sessionFactory) { + LoaderSqlAstCreationState creationState) { final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); final QuerySpec subQuery = new QuerySpec( false ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/NoCallbackExecutionContext.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/NoCallbackExecutionContext.java index be53c01f2b..2e8726467e 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/NoCallbackExecutionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/NoCallbackExecutionContext.java @@ -7,7 +7,6 @@ package org.hibernate.loader.ast.internal; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.sql.exec.internal.BaseExecutionContext; import org.hibernate.sql.exec.spi.Callback; @@ -19,7 +18,8 @@ public class NoCallbackExecutionContext extends BaseExecutionContext { @Override public Callback getCallback() { - throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); + return null; +// throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 72e0fe277a..76596c8a20 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -16,7 +16,6 @@ import java.util.StringTokenizer; import org.hibernate.HibernateException; import org.hibernate.Internal; import org.hibernate.MappingException; -import org.hibernate.PropertyNotFoundException; import org.hibernate.boot.model.relational.Database; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.engine.spi.CascadeStyle; @@ -138,12 +137,16 @@ public class Property implements Serializable, MetaAttributable { } } - public boolean isPrimitive(Class clazz) { - return getGetter(clazz).getReturnTypeClass().isPrimitive(); + /** + * @deprecated this method is no longer used + */ + @Deprecated(since = "6", forRemoval = true) + public boolean isPrimitive(Class clazz) { + return getGetter( clazz ).getReturnTypeClass().isPrimitive(); } public CascadeStyle getCascadeStyle() throws MappingException { - Type type = value.getType(); + final Type type = value.getType(); if ( type.isComponentType() ) { return getCompositeCascadeStyle( (CompositeType) type, cascade ); } @@ -292,28 +295,27 @@ public class Property implements Serializable, MetaAttributable { /** * Is this property lazy in the "bytecode" sense? *

- * Lazy here means whether we should push *something* to the entity - * instance for this field in its "base fetch group". Mainly it affects - * whether we should list this property's columns in the SQL select - * for the owning entity when we load its "base fetch group". - *

- * The "something" we push varies based on the nature (basic, etc) of - * the property. + * Lazy here means whether we initialize this field of the entity + * instance in its "base fetch group". It affects whether we list + * this property's columns in the SQL select for the owning entity + * when we load its "base fetch group". The actual value that is set + * varies based on the nature (basic, etc) of the property. * - * @apiNote This form reports whether the property is considered part of the - * base fetch group based solely on the mapping information. However, - * {@link EnhancementHelper#includeInBaseFetchGroup} is used internally to make that - * decision to account for other details + * @apiNote This method reports whether the property is considered + * part of the base fetch group based solely on the information in + * the mapping but {@link EnhancementHelper#includeInBaseFetchGroup} + * is also accounts for other details. */ public boolean isLazy() { if ( value instanceof ToOne ) { - // For a many-to-one, this is always false. Whether the - // association is EAGER, PROXY or NO-PROXY we want the fk - // selected + // For a many-to-one, this is always false. Whether the + // association is EAGER, PROXY or NO-PROXY we always want + // to select the foreign key return false; } - - return lazy; + else { + return lazy; + } } public String getLazyGroup() { @@ -333,7 +335,7 @@ public class Property implements Serializable, MetaAttributable { } public boolean isOptional() { - return optional || isNullable(); + return optional; } public void setOptional(boolean optional) { @@ -361,12 +363,12 @@ public class Property implements Serializable, MetaAttributable { } // todo : remove - public Getter getGetter(Class clazz) throws PropertyNotFoundException, MappingException { + public Getter getGetter(Class clazz) throws MappingException { return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getGetter(); } // todo : remove - public Setter getSetter(Class clazz) throws PropertyNotFoundException, MappingException { + public Setter getSetter(Class clazz) throws MappingException { return getPropertyAccessStrategy( clazz ).buildPropertyAccess( clazz, name, true ).getSetter(); } @@ -454,27 +456,27 @@ public class Property implements Serializable, MetaAttributable { } public Property copy() { - final Property prop = new Property(); - prop.setName( getName() ); - prop.setValue( getValue() ); - prop.setCascade( getCascade() ); - prop.setUpdateable( isUpdateable() ); - prop.setInsertable( isInsertable() ); - prop.setSelectable( isSelectable() ); - prop.setOptimisticLocked( isOptimisticLocked() ); - prop.setValueGeneratorCreator( getValueGeneratorCreator() ); - prop.setPropertyAccessorName( getPropertyAccessorName() ); - prop.setPropertyAccessStrategy( getPropertyAccessStrategy() ); - prop.setLazy( isLazy() ); - prop.setLazyGroup( getLazyGroup() ); - prop.setOptional( isOptional() ); - prop.setMetaAttributes( getMetaAttributes() ); - prop.setPersistentClass( getPersistentClass() ); - prop.setNaturalIdentifier( isNaturalIdentifier() ); - prop.setLob( isLob() ); - prop.addCallbackDefinitions( getCallbackDefinitions() ); - prop.setReturnedClassName( getReturnedClassName() ); - return prop; + final Property property = new Property(); + property.setName( getName() ); + property.setValue( getValue() ); + property.setCascade( getCascade() ); + property.setUpdateable( isUpdateable() ); + property.setInsertable( isInsertable() ); + property.setSelectable( isSelectable() ); + property.setOptimisticLocked( isOptimisticLocked() ); + property.setValueGeneratorCreator( getValueGeneratorCreator() ); + property.setPropertyAccessorName( getPropertyAccessorName() ); + property.setPropertyAccessStrategy( getPropertyAccessStrategy() ); + property.setLazy( isLazy() ); + property.setLazyGroup( getLazyGroup() ); + property.setOptional( isOptional() ); + property.setMetaAttributes( getMetaAttributes() ); + property.setPersistentClass( getPersistentClass() ); + property.setNaturalIdentifier( isNaturalIdentifier() ); + property.setLob( isLob() ); + property.addCallbackDefinitions( getCallbackDefinitions() ); + property.setReturnedClassName( getReturnedClassName() ); + return property; } private class PropertyGeneratorCreationContext implements GeneratorCreationContext { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index ed2efde761..c252c5f3fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -554,7 +554,7 @@ public abstract class AbstractEntityPersister throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName() + "] : " + bootDescriptor.getLoaderName() ); } - singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>(this, namedQueryMemento ); + singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, namedQueryMemento ); } else if ( batchSize > 1 ) { singleIdEntityLoader = createBatchingIdEntityLoader( this, batchSize, factory ); @@ -4723,17 +4723,17 @@ public abstract class AbstractEntityPersister creationProcess.registerInitializationCallback( "Entity(" + getEntityName() + ") `staticFetchableList` generator", () -> { + final ImmutableAttributeMappingList.Builder builder = + new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); + visitSubTypeAttributeMappings( builder::add ); + assert superMappingType != null || builder.assertFetchableIndexes(); + staticFetchableList = builder.build(); if ( hasInsertGeneratedProperties() ) { insertGeneratedValuesProcessor = createGeneratedValuesProcessor( INSERT ); } if ( hasUpdateGeneratedProperties() ) { updateGeneratedValuesProcessor = createGeneratedValuesProcessor( UPDATE ); } - final ImmutableAttributeMappingList.Builder builder = - new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); - visitSubTypeAttributeMappings( builder::add ); - assert superMappingType != null || builder.assertFetchableIndexes(); - staticFetchableList = builder.build(); return true; } ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/SelectStatement.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/SelectStatement.java index 55244e02db..bc7a6def7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/SelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/SelectStatement.java @@ -21,12 +21,10 @@ import org.hibernate.sql.ast.tree.AbstractStatement; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.cte.CteContainer; import org.hibernate.sql.ast.tree.cte.CteStatement; -import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.basic.BasicResult; -import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/various/OneOneGeneratedValueTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/various/OneOneGeneratedValueTest.java index d1ac8555db..702d32faf6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/various/OneOneGeneratedValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/various/OneOneGeneratedValueTest.java @@ -10,10 +10,8 @@ import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.junit.jupiter.api.Test; -import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToOne; import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.Table; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/nullable/B.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/nullable/B.java index 1bd8b6f3c1..94db3d7c9c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/nullable/B.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/nullable/B.java @@ -6,6 +6,7 @@ */ package org.hibernate.orm.test.mapping.naturalid.nullable; +import jakarta.persistence.Basic; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne;