diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/ModelBindingLogging.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/ModelBindingLogging.java index 29ad70e975..5e6d5c7329 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/ModelBindingLogging.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/ModelBindingLogging.java @@ -10,6 +10,12 @@ import org.hibernate.Internal; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.logging.annotations.ValidIdRange; + +import static org.jboss.logging.Logger.Level.INFO; /** * todo : find the proper min/max id range @@ -17,8 +23,19 @@ import org.jboss.logging.Logger; * @author Steve Ebersole */ @Internal +@MessageLogger( projectCode = "HHH" ) +@ValidIdRange( min = 999980, max = 999999 ) public interface ModelBindingLogging extends BasicLogger { String NAME = "org.hibernate.models.orm"; Logger MODEL_BINDING_LOGGER = Logger.getLogger( NAME ); + ModelBindingLogging MODEL_BINDING_MSG_LOGGER = Logger.getMessageLogger( ModelBindingLogging.class, NAME ); + + @LogMessage(level = INFO) + @Message( id = 999980, value = "Entity `%s` used both @DynamicInsert and @SQLInsert" ) + void dynamicAndCustomInsert(String entityName); + + @LogMessage(level = INFO) + @Message( id = 999981, value = "Entity `%s` used both @DynamicUpdate and @SQLUpdate" ) + void dynamicAndCustomUpdate(String entityName); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/AttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/AttributeBinding.java index f1ebdb371c..ec96b092be 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/AttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/AttributeBinding.java @@ -35,6 +35,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Convert; import static org.hibernate.boot.models.categorize.spi.AttributeMetadata.AttributeNature.BASIC; +import static org.hibernate.boot.models.categorize.spi.AttributeMetadata.AttributeNature.EMBEDDED; /** * Binding for an attribute @@ -61,16 +62,21 @@ public class AttributeBinding extends Binding { this.property = new Property(); this.property.setName( attributeMetadata.getName() ); + final Value value; if ( attributeMetadata.getNature() == BASIC ) { - final var basicValue = createBasicValue( primaryTable ); - property.setValue( basicValue ); - attributeTable = basicValue.getTable(); - mappingValue = basicValue; + value = createBasicValue( primaryTable ); + } + else if ( attributeMetadata.getNature() == EMBEDDED ) { + value = createComponentValue( primaryTable, owner ); } else { throw new UnsupportedOperationException( "Not yet implemented" ); } + property.setValue( value ); + attributeTable = value.getTable(); + mappingValue = value; + applyNaturalId( attributeMetadata, property ); } @@ -132,6 +138,16 @@ public class AttributeBinding extends Binding { return basicValue; } + private Component createComponentValue(Table primaryTable, PersistentClass persistentClass) { + final Component component = new Component( bindingState.getMetadataBuildingContext(), persistentClass ); + + // 1. embeddable (attributes, etc) + // 2. overrides + final MemberDetails member = attributeMetadata.getMember(); + + return component; + } + public Property getProperty() { return property; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BindingHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BindingHelper.java index 1141394fdb..6d977a367d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BindingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BindingHelper.java @@ -13,7 +13,6 @@ import java.util.function.Supplier; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ObjectNameNormalizer; -import org.hibernate.boot.models.bind.spi.BindingContext; import org.hibernate.boot.models.bind.spi.BindingOptions; import org.hibernate.boot.models.bind.spi.BindingState; import org.hibernate.boot.models.bind.spi.QuotedIdentifierTarget; @@ -21,7 +20,6 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.models.ModelsException; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationUsage; -import org.hibernate.models.spi.AttributeDescriptor; import static org.hibernate.boot.models.bind.ModelBindingLogging.MODEL_BINDING_LOGGER; @@ -29,69 +27,6 @@ import static org.hibernate.boot.models.bind.ModelBindingLogging.MODEL_BINDING_L * @author Steve Ebersole */ public class BindingHelper { - public static T getValue( - AnnotationUsage annotationUsage, - String attributeName, - Class annotationType, - BindingContext context) { - final T valueOrNull = getValueOrNull( annotationUsage, attributeName ); - if ( valueOrNull != null ) { - return valueOrNull; - } - - // resolve its default - return getDefaultValue( attributeName, annotationType, context ); - } - - public static T getValueOrNull( - AnnotationUsage annotationUsage, - String attributeName) { - if ( annotationUsage != null ) { - // allow to return null if missing - return annotationUsage.getAttributeValue( attributeName ); - } - - // there was no annotation... - return null; - } - - public static T getDefaultValue( - String attributeName, - Class annotationType, - BindingContext context) { - final AnnotationDescriptor annotationDescriptor = context.getAnnotationDescriptorRegistry().getDescriptor( annotationType ); - final AttributeDescriptor attributeDescriptor = annotationDescriptor.getAttribute( attributeName ); - //noinspection unchecked - return (T) attributeDescriptor.getAttributeMethod().getDefaultValue(); - - } - - public static String getString( - AnnotationUsage annotationUsage, - String attributeName, - Class annotationType, - BindingContext context) { - return getValue( annotationUsage, attributeName, annotationType, context ); - } - - public static String getStringOrNull( - AnnotationUsage annotationUsage, - String attributeName) { - return getValueOrNull( annotationUsage, attributeName ); - } - - public static Identifier getIdentifier( - AnnotationUsage annotationUsage, - String attributeName, - Class annotationType, - QuotedIdentifierTarget target, - BindingOptions options, - JdbcEnvironment jdbcEnvironment, - BindingContext context) { - final String name = getString( annotationUsage, attributeName, annotationType, context ); - final boolean globallyQuoted = options.getGloballyQuotedIdentifierTargets().contains( target ); - return jdbcEnvironment.getIdentifierHelper().toIdentifier( name, globallyQuoted ); - } public static Identifier toIdentifier( String name, @@ -116,17 +51,12 @@ public class BindingHelper { return (T) descriptor.getAttribute( attributeName ).getAttributeMethod().getDefaultValue(); } - //noinspection unchecked - return getValue( - ann, - attributeName, - () -> (T) descriptor.getAttribute( attributeName ).getAttributeMethod().getDefaultValue() - ); + return ann.getAttributeValue( attributeName ); } public static T getValue(AnnotationUsage ann, String attributeName, Supplier defaultValueSupplier) { if ( ann == null ) { - return (T) defaultValueSupplier.get(); + return defaultValueSupplier.get(); } return ann.getAttributeValue( attributeName, defaultValueSupplier ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/EntityBinding.java index 07d8f562ee..1623b64d54 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/EntityBinding.java @@ -6,14 +6,26 @@ */ package org.hibernate.boot.models.bind.internal; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.Filter; +import org.hibernate.annotations.ResultCheckStyle; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLInsert; +import org.hibernate.annotations.SQLUpdate; +import org.hibernate.annotations.Synchronize; +import org.hibernate.boot.models.HibernateAnnotations; import org.hibernate.boot.models.bind.spi.BindingContext; import org.hibernate.boot.models.bind.spi.BindingOptions; import org.hibernate.boot.models.bind.spi.BindingState; @@ -24,6 +36,7 @@ import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata; import org.hibernate.boot.models.categorize.spi.JpaEventListener; import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; import org.hibernate.boot.models.categorize.spi.MappedSuperclassTypeMetadata; +import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.event.internal.EntityCallback; @@ -44,6 +57,8 @@ import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; import jakarta.persistence.SharedCacheMode; +import static org.hibernate.boot.models.bind.ModelBindingLogging.MODEL_BINDING_MSG_LOGGER; + /** * @author Steve Ebersole */ @@ -96,6 +111,15 @@ public abstract class EntityBinding extends IdentifiableTypeBinding { bindingState.getMetadataBuildingContext().getMetadataCollector().addImport( importName, entityName ); } + protected static void applyCommonInformation(EntityTypeMetadata typeMetadata, PersistentClass persistentClass, BindingState bindingState) { + applyCaching( typeMetadata, persistentClass, bindingState ); + applyFilters( typeMetadata, persistentClass ); + applyJpaEventListeners( typeMetadata, persistentClass ); + applyBatchSize( typeMetadata, persistentClass, bindingState ); + applySqlCustomizations( typeMetadata, persistentClass, bindingState ); + applySynchronizedTableNames( typeMetadata, persistentClass, bindingState ); + } + protected static void applyDiscriminatorValue( EntityTypeMetadata typeMetadata, PersistentClass persistentClass) { @@ -357,6 +381,153 @@ public abstract class EntityBinding extends IdentifiableTypeBinding { } } + private static void applyBatchSize( + EntityTypeMetadata typeMetadata, + PersistentClass persistentClass, + BindingState bindingState) { + final AnnotationUsage batchSizeAnnotation = typeMetadata + .getClassDetails() + .getAnnotationUsage( HibernateAnnotations.BATCH_SIZE ); + if ( batchSizeAnnotation == null ) { + return; + } + + persistentClass.setBatchSize( batchSizeAnnotation.getInteger( "size" ) ); + } + + private static void applySqlCustomizations( + EntityTypeMetadata typeMetadata, + PersistentClass persistentClass, + BindingState bindingState) { + final AnnotationUsage dynamicInsert = typeMetadata + .getClassDetails() + .getAnnotationUsage( HibernateAnnotations.DYNAMIC_INSERT ); + final AnnotationUsage dynamicUpdate = typeMetadata + .getClassDetails() + .getAnnotationUsage( HibernateAnnotations.DYNAMIC_UPDATE ); + + final List> customInserts = typeMetadata + .getClassDetails() + .getRepeatedAnnotationUsages( HibernateAnnotations.SQL_INSERT ); + final List> customUpdates = typeMetadata + .getClassDetails() + .getRepeatedAnnotationUsages( HibernateAnnotations.SQL_UPDATE ); + final List> customDeletes = typeMetadata + .getClassDetails() + .getRepeatedAnnotationUsages( HibernateAnnotations.SQL_DELETE ); + + if ( dynamicInsert != null ) { + if ( CollectionHelper.isNotEmpty( customInserts ) ) { + MODEL_BINDING_MSG_LOGGER.dynamicAndCustomInsert( persistentClass.getEntityName() ); + } + persistentClass.setDynamicInsert( dynamicInsert.getBoolean( "value" ) ); + } + + if ( dynamicUpdate != null ) { + if ( CollectionHelper.isNotEmpty( customUpdates ) ) { + MODEL_BINDING_MSG_LOGGER.dynamicAndCustomUpdate( persistentClass.getEntityName() ); + } + persistentClass.setDynamicUpdate( dynamicUpdate.getBoolean( "value" ) ); + } + + if ( CollectionHelper.isNotEmpty( customInserts ) + || CollectionHelper.isNotEmpty( customUpdates ) + || CollectionHelper.isNotEmpty( customDeletes ) ) { + final Map joinMap = extractJoinMap( persistentClass ); + applyCustomSql( + customInserts, + persistentClass, + joinMap, + PersistentClass::setCustomSQLInsert, + Join::setCustomSQLInsert + ); + applyCustomSql( + customUpdates, + persistentClass, + joinMap, + PersistentClass::setCustomSQLUpdate, + Join::setCustomSQLUpdate + ); + applyCustomSql( + customDeletes, + persistentClass, + joinMap, + PersistentClass::setCustomSQLDelete, + Join::setCustomSQLDelete + ); + } + } + + private static Map extractJoinMap(PersistentClass persistentClass) { + final List joins = persistentClass.getJoins(); + if ( CollectionHelper.isEmpty( joins ) ) { + return Collections.emptyMap(); + } + + final HashMap joinMap = CollectionHelper.mapOfSize( joins.size() ); + joins.forEach( (join) -> joinMap.put( join.getTable().getName(), join ) ); + return joinMap; + } + + private static void applyCustomSql( + List> annotationUsages, + PersistentClass persistentClass, + Map joinMap, + PrimaryCustomSqlInjector primaryTableInjector, + SecondaryCustomSqlInjector secondaryTableInjector) { + if ( CollectionHelper.isEmpty( annotationUsages ) ) { + return; + } + + annotationUsages.forEach( annotationUsage -> { + final String tableName = annotationUsage.getString( "table" ); + + if ( StringHelper.isEmpty( tableName ) ) { + primaryTableInjector.injectCustomSql( + persistentClass, + annotationUsage.getString( "sql" ), + annotationUsage.getBoolean( "callable" ), + ExecuteUpdateResultCheckStyle.fromResultCheckStyle( annotationUsage.getEnum( "", ResultCheckStyle.class ) ) + ); + } + else { + final Join join = joinMap.get( tableName ); + secondaryTableInjector.injectCustomSql( + join, + annotationUsage.getString( "sql" ), + annotationUsage.getBoolean( "callable" ), + ExecuteUpdateResultCheckStyle.fromResultCheckStyle( annotationUsage.getEnum( "", ResultCheckStyle.class ) ) + ); + } + } ); + } + + @FunctionalInterface + private interface PrimaryCustomSqlInjector { + void injectCustomSql(PersistentClass persistentClass, String sql, boolean callable, ExecuteUpdateResultCheckStyle checkStyle); + } + + @FunctionalInterface + private interface SecondaryCustomSqlInjector { + void injectCustomSql(Join join, String sql, boolean callable, ExecuteUpdateResultCheckStyle checkStyle); + } + + private static void applySynchronizedTableNames( + EntityTypeMetadata typeMetadata, + PersistentClass persistentClass, + BindingState bindingState) { + final AnnotationUsage usage = typeMetadata + .getClassDetails() + .getAnnotationUsage( HibernateAnnotations.SYNCHRONIZE ); + if ( usage == null ) { + return; + } + + // todo : handle Synchronize#logical - for now assume it is logical + final List names = usage.getList( "value" ); + names.forEach( persistentClass::addSynchronizedTable ); + } + protected void processSecondaryTables(TableReference primaryTableReference) { TableHelper.bindSecondaryTables( this, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/RootEntityBinding.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/RootEntityBinding.java index df0d648b98..ba3757b5b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/RootEntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/RootEntityBinding.java @@ -107,12 +107,8 @@ public class RootEntityBinding extends EntityBinding { applyCacheRegions( typeMetadata, rootClass ); applySoftDelete( typeMetadata, rootClass, tableReference.table() ); - applyCaching( typeMetadata, rootClass, bindingState ); - applyFilters( typeMetadata, rootClass ); - applyJpaEventListeners( typeMetadata, rootClass ); - + applyCommonInformation( typeMetadata, rootClass, bindingState ); prepareAttributeBindings( tableReference.table() ); - prepareSubclassBindings(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/SubclassEntityBinding.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/SubclassEntityBinding.java index 0dbef6beb5..e3dbf8e538 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/SubclassEntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/SubclassEntityBinding.java @@ -40,21 +40,21 @@ public class SubclassEntityBinding extends EntityBinding { private final Subclass subclass; public SubclassEntityBinding( - EntityTypeMetadata entityTypeMetadata, + EntityTypeMetadata typeMetadata, IdentifiableTypeBinding superTypeBinding, EntityHierarchy.HierarchyRelation hierarchyRelation, BindingOptions bindingOptions, BindingState bindingState, BindingContext bindingContext) { - super( entityTypeMetadata, superTypeBinding, hierarchyRelation, bindingOptions, bindingState, bindingContext ); + super( typeMetadata, superTypeBinding, hierarchyRelation, bindingOptions, bindingState, bindingContext ); this.subclass = createSubclass(); - applyNaming( entityTypeMetadata, subclass, bindingState ); + applyNaming( typeMetadata, subclass, bindingState ); bindingState.registerTypeBinding( getTypeMetadata(), this ); if ( subclass instanceof TableOwner ) { final var primaryTable = TableHelper.bindPrimaryTable( - entityTypeMetadata, + typeMetadata, EntityHierarchy.HierarchyRelation.SUB, bindingOptions, bindingState, @@ -64,7 +64,11 @@ public class SubclassEntityBinding extends EntityBinding { ( (TableOwner) subclass ).setTable( table ); } - applyDiscriminatorValue( getTypeMetadata(), subclass ); + applyDiscriminatorValue( typeMetadata, subclass ); + + applyCommonInformation( typeMetadata, subclass, bindingState ); + prepareAttributeBindings( subclass.getTable() ); + prepareSubclassBindings(); } @Override @@ -182,10 +186,10 @@ public class SubclassEntityBinding extends EntityBinding { final AnnotationUsage foreignKeyAnn = BindingHelper.getValue( joinTableAnn, "foreignKey", (AnnotationUsage) null ); final String foreignKeyName = foreignKeyAnn == null ? "" - : BindingHelper.getString( foreignKeyAnn, "name", ForeignKey.class, bindingContext ); + : foreignKeyAnn.getString( "name" ); final String foreignKeyDefinition = foreignKeyAnn == null ? "" - : BindingHelper.getString( foreignKeyAnn, "foreignKeyDefinition", ForeignKey.class, bindingContext ); + : foreignKeyAnn.getString( "foreignKeyDefinition" ); final org.hibernate.mapping.ForeignKey foreignKey = targetTable.createForeignKey( foreignKeyName, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/TableHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/TableHelper.java index f4a22a55ab..a2e6107f5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/TableHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/TableHelper.java @@ -7,7 +7,6 @@ package org.hibernate.boot.models.bind.internal; import java.lang.annotation.Annotation; -import java.util.ArrayList; import java.util.List; import org.hibernate.annotations.Comment; @@ -75,7 +74,6 @@ public class TableHelper { tableReference = bindPhysicalTable( entityTypeMetadata, tableAnn, - Table.class, true, bindingOptions, bindingState, @@ -178,7 +176,6 @@ public class TableHelper { final Identifier schemaName = resolveDatabaseIdentifier( secondaryTableAnn, "schema", - jakarta.persistence.SecondaryTable.class, bindingOptions.getDefaultSchemaName(), QuotedIdentifierTarget.SCHEMA_NAME, bindingOptions, @@ -188,7 +185,6 @@ public class TableHelper { final Identifier catalogName = resolveDatabaseIdentifier( secondaryTableAnn, "catalog", - jakarta.persistence.SecondaryTable.class, bindingOptions.getDefaultCatalogName(), QuotedIdentifierTarget.CATALOG_NAME, bindingOptions, @@ -249,7 +245,7 @@ public class TableHelper { } else { // either an explicit or implicit @Table - tableReference = bindPhysicalTable( type, tableAnn, annotationType, true, bindingOptions, bindingState, bindingContext ); + tableReference = bindPhysicalTable( type, tableAnn, true, bindingOptions, bindingState, bindingContext ); } return tableReference; } @@ -281,7 +277,7 @@ public class TableHelper { null, null, logicalName.getCanonicalName(), - BindingHelper.getString( subselectAnn, "value", Subselect.class, bindingContext ), + subselectAnn.getString( "value" ), true, bindingState.getMetadataBuildingContext() ) @@ -291,13 +287,12 @@ public class TableHelper { private static PhysicalTableReference bindPhysicalTable( EntityTypeMetadata type, AnnotationUsage tableAnn, - Class annotationType, boolean isPrimary, BindingOptions bindingOptions, BindingState bindingState, BindingContext bindingContext) { if ( tableAnn != null ) { - return bindExplicitPhysicalTable( type, tableAnn, annotationType, isPrimary, bindingOptions, bindingState, bindingContext ); + return bindExplicitPhysicalTable( type, tableAnn, isPrimary, bindingOptions, bindingState, bindingContext ); } else { return bindImplicitPhysicalTable( type, isPrimary, bindingOptions, bindingState, bindingContext ); @@ -307,7 +302,6 @@ public class TableHelper { private static PhysicalTable bindExplicitPhysicalTable( EntityTypeMetadata type, AnnotationUsage tableAnn, - Class annotationType, boolean isPrimary, BindingOptions bindingOptions, BindingState bindingState, @@ -316,7 +310,6 @@ public class TableHelper { final Identifier logicalSchemaName = resolveDatabaseIdentifier( tableAnn, "schema", - annotationType, bindingOptions.getDefaultSchemaName(), QuotedIdentifierTarget.SCHEMA_NAME, bindingOptions, @@ -326,7 +319,6 @@ public class TableHelper { final Identifier logicalCatalogName = resolveDatabaseIdentifier( tableAnn, "catalog", - annotationType, bindingOptions.getDefaultCatalogName(), QuotedIdentifierTarget.CATALOG_NAME, bindingOptions, @@ -412,7 +404,6 @@ public class TableHelper { final Identifier logicalSchemaName = resolveDatabaseIdentifier( tableAnn, "schema", - Table.class, bindingOptions.getDefaultSchemaName(), QuotedIdentifierTarget.SCHEMA_NAME, bindingOptions, @@ -422,7 +413,6 @@ public class TableHelper { final Identifier logicalCatalogName = resolveDatabaseIdentifier( tableAnn, "catalog", - Table.class, bindingOptions.getDefaultCatalogName(), QuotedIdentifierTarget.CATALOG_NAME, bindingOptions, @@ -486,23 +476,24 @@ public class TableHelper { private static Identifier resolveDatabaseIdentifier( AnnotationUsage annotationUsage, String attributeName, - Class annotationType, Identifier fallback, QuotedIdentifierTarget target, BindingOptions bindingOptions, - BindingState bindingState, + @SuppressWarnings("unused") BindingState bindingState, BindingContext bindingContext) { - final String explicit = BindingHelper.getStringOrNull( annotationUsage, attributeName ); - if ( StringHelper.isNotEmpty( explicit ) ) { - return BindingHelper.toIdentifier( explicit, target, bindingOptions, jdbcEnvironment( bindingContext ) ); - } - - if ( fallback != null ) { + if ( annotationUsage == null ) { return fallback; } - - final String defaultValue = BindingHelper.getDefaultValue( attributeName, annotationType, bindingContext ); - return BindingHelper.toIdentifier(defaultValue, target, bindingOptions, jdbcEnvironment( bindingContext ) ); + final String explicitValue = annotationUsage.getString( attributeName ); + if ( StringHelper.isEmpty( explicitValue ) ) { + return fallback; + } + return BindingHelper.toIdentifier( + explicitValue, + target, + bindingOptions, + jdbcEnvironment( bindingContext ) + ); } private static AnnotationUsage findCommentAnnotation( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/ModelCategorizationLogging.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/ModelCategorizationLogging.java index c9aa04965d..099727d816 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/ModelCategorizationLogging.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/ModelCategorizationLogging.java @@ -8,14 +8,7 @@ package org.hibernate.boot.models.categorize; import org.hibernate.Internal; -import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; -import org.jboss.logging.annotations.LogMessage; -import org.jboss.logging.annotations.Message; -import org.jboss.logging.annotations.MessageLogger; -import org.jboss.logging.annotations.ValidIdRange; - -import static org.jboss.logging.Logger.Level.INFO; /** * todo : find the proper min/max id range @@ -23,19 +16,8 @@ import static org.jboss.logging.Logger.Level.INFO; * @author Steve Ebersole */ @Internal -@MessageLogger( projectCode = "HHH" ) -@ValidIdRange( min = 999901, max = 999999 ) -public interface ModelCategorizationLogging extends BasicLogger { +public interface ModelCategorizationLogging { String NAME = "org.hibernate.models.orm"; Logger MODEL_CATEGORIZATION_LOGGER = Logger.getLogger( NAME ); - ModelCategorizationLogging MODEL_CATEGORIZATION_MSG_LOGGER = Logger.getMessageLogger( ModelCategorizationLogging.class, NAME ); - - @LogMessage(level = INFO) - @Message( id = 999901, value = "Entity `%s` used both @DynamicInsert and @SQLInsert" ) - void dynamicAndCustomInsert(String entityName); - - @LogMessage(level = INFO) - @Message( id = 999902, value = "Entity `%s` used both @DynamicUpdate and @SQLUpdate" ) - void dynamicAndCustomUpdate(String entityName); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleBindingCoordinatorTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleBindingCoordinatorTests.java index 9d5753980f..f5604a9a6e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleBindingCoordinatorTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleBindingCoordinatorTests.java @@ -28,13 +28,13 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Steve Ebersole */ +@ServiceRegistry( settingProviders = @SettingProvider( + settingName = AvailableSettings.PHYSICAL_NAMING_STRATEGY, + provider = CustomNamingStrategyProvider.class +) ) public class SimpleBindingCoordinatorTests { @Test - @ServiceRegistry( settingProviders = @SettingProvider( - settingName = AvailableSettings.PHYSICAL_NAMING_STRATEGY, - provider = CustomNamingStrategyProvider.class - ) ) - void testIt(ServiceRegistryScope scope) { + void testCollectorState(ServiceRegistryScope scope) { BindingTestingHelper.checkDomainModel( (context) -> { final var bindingState = context.getBindingState(); @@ -75,15 +75,17 @@ public class SimpleBindingCoordinatorTests { assertThat( namespaceItr.hasNext() ).isFalse(); assertThat( namespace1.getTables() ).hasSize( 1 ); assertThat( namespace2.getTables() ).hasSize( 1 ); + }, + scope.getRegistry(), + SimpleEntity.class + ); + } + @Test + void testAttributes(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); - assertThat( entityBinding.isCached() ).isFalse(); - final Column softDeleteColumn = entityBinding.getSoftDeleteColumn(); - assertThat( softDeleteColumn ).isNotNull(); - assertThat( softDeleteColumn.getName() ).isEqualTo( "ACTIVE" ); - assertThat( entityBinding.getFilters() ).hasSize( 1 ); - assertThat( entityBinding.getCacheRegionName() ).isEqualTo( "my-region" ); - assertThat( entityBinding.getCacheConcurrencyStrategy() ).isEqualTo( CacheConcurrencyStrategy.READ_ONLY.toAccessType().getExternalName() ); final Property id = entityBinding.getProperty( "id" ); assertThat( id.getValue().getTable().getName() ).isEqualTo( "SIMPLETONS" ); @@ -125,4 +127,74 @@ public class SimpleBindingCoordinatorTests { SimpleEntity.class ); } + + @Test + void testCaching(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { + final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); + assertThat( entityBinding.isCached() ).isFalse(); + assertThat( entityBinding.getCacheRegionName() ).isEqualTo( "my-region" ); + assertThat( entityBinding.getCacheConcurrencyStrategy() ).isEqualTo( CacheConcurrencyStrategy.READ_ONLY.toAccessType().getExternalName() ); + + }, + scope.getRegistry(), + SimpleEntity.class + ); + } + + @Test + void testBatchSize(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { + final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); + assertThat( entityBinding.getBatchSize() ).isEqualTo( 32 ); + }, + scope.getRegistry(), + SimpleEntity.class + ); + } + + @Test + void testSoftDelete(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { + final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); + + final Column softDeleteColumn = entityBinding.getSoftDeleteColumn(); + assertThat( softDeleteColumn ).isNotNull(); + assertThat( softDeleteColumn.getName() ).isEqualTo( "ACTIVE" ); + + }, + scope.getRegistry(), + SimpleEntity.class + ); + } + + @Test + void testSynchronization(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { + final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); + + assertThat( entityBinding.getSynchronizedTables() ).hasSize( 1 ); + + assertThat( entityBinding.getFilters() ).hasSize( 1 ); + }, + scope.getRegistry(), + SimpleEntity.class + ); + } + + @Test + void testFilters(ServiceRegistryScope scope) { + BindingTestingHelper.checkDomainModel( + (context) -> { + final RootClass entityBinding = (RootClass) context.getMetadataCollector().getEntityBinding( SimpleEntity.class.getName() ); + assertThat( entityBinding.getFilters() ).hasSize( 1 ); + }, + scope.getRegistry(), + SimpleEntity.class + ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleEntity.java index 69ff18aff5..22042bae24 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/SimpleEntity.java @@ -6,6 +6,7 @@ */ package org.hibernate.orm.test.boot.models.bind; +import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Filter; @@ -13,6 +14,7 @@ import org.hibernate.annotations.FilterDef; import org.hibernate.annotations.ParamDef; import org.hibernate.annotations.SoftDelete; import org.hibernate.annotations.SoftDeleteType; +import org.hibernate.annotations.Synchronize; import org.hibernate.annotations.TenantId; import jakarta.persistence.Basic; @@ -39,6 +41,8 @@ import jakarta.persistence.Version; @SoftDelete(strategy = SoftDeleteType.ACTIVE) @Cacheable(false) @Cache(usage = CacheConcurrencyStrategy.READ_ONLY, region = "my-region") +@BatchSize(size = 32) +@Synchronize("some_other_table") public class SimpleEntity { @Id private Integer id;