HHH-15934 correctly handle @Basic(optional=false)

previously it had no effect
This commit is contained in:
Gavin 2022-12-25 18:15:56 +01:00 committed by Gavin King
parent 9e9a363154
commit 218ace291f
14 changed files with 263 additions and 251 deletions

View File

@ -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<XClass, InheritanceState> 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,

View File

@ -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<Object> 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<? extends BasicJavaType<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() );
if ( jdbcTypeImpl != null ) {
final ManagedBean<? extends BasicJavaType> jdbcTypeBean = getManagedBeanRegistry().getBean( jdbcTypeImpl );
return jdbcTypeBean.getBeanInstance();
return getManagedBeanRegistry().getBean( jdbcTypeImpl ).getBeanInstance();
}
}

View File

@ -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() );

View File

@ -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() );

View File

@ -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<? extends EmbeddableInstantiator> 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'" );
}

View File

@ -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 ),

View File

@ -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 );
}
}

View File

@ -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<JdbcParameter> jdbcParameterConsumer,
@ -244,7 +240,7 @@ public class LoaderSelectBuilder {
private final Loadable loadable;
private final List<? extends ModelPart> partsToSelect;
private final List<ModelPart> 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<? extends ModelPart> partsToSelect,
List<ModelPart> restrictedParts,
DomainResult cachedDomainResult,
DomainResult<?> cachedDomainResult,
int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions,
@ -287,7 +283,7 @@ public class LoaderSelectBuilder {
Loadable loadable,
List<? extends ModelPart> partsToSelect,
List<ModelPart> restrictedParts,
DomainResult cachedDomainResult,
DomainResult<?> cachedDomainResult,
int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions,
@ -312,7 +308,7 @@ public class LoaderSelectBuilder {
Loadable loadable,
List<? extends ModelPart> 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<Fetchable, Boolean> processor = createFetchableBiConsumer(
fetchParent,
creationState,
fetches
);
final BiConsumer<Fetchable, Boolean> 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 );

View File

@ -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" );
}
}

View File

@ -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?
* <p>
* 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".
* <p>
* 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 {

View File

@ -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;
}
);

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;