HHH-17504 - Ongoing JPA 32 work
HHH-17350 - Work on hibernate-models, XSD and JAXB HHH-16114 - Improve boot metamodel binding HHH-15996 - Develop an abstraction for Annotation in annotation processing HHH-16012 - Develop an abstraction for domain model Class refs HHH-15997 - Support for dynamic models in orm.xml HHH-15698 - Support for entity-name in mapping.xsd
This commit is contained in:
parent
3e20e0939f
commit
2eb3da331b
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, A extends Annotation> T getValue(
|
||||
AnnotationUsage<A> annotationUsage,
|
||||
String attributeName,
|
||||
Class<A> 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, A extends Annotation> T getValueOrNull(
|
||||
AnnotationUsage<A> 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,A extends Annotation> T getDefaultValue(
|
||||
String attributeName,
|
||||
Class<A> annotationType,
|
||||
BindingContext context) {
|
||||
final AnnotationDescriptor<A> annotationDescriptor = context.getAnnotationDescriptorRegistry().getDescriptor( annotationType );
|
||||
final AttributeDescriptor<Object> attributeDescriptor = annotationDescriptor.getAttribute( attributeName );
|
||||
//noinspection unchecked
|
||||
return (T) attributeDescriptor.getAttributeMethod().getDefaultValue();
|
||||
|
||||
}
|
||||
|
||||
public static <A extends Annotation> String getString(
|
||||
AnnotationUsage<A> annotationUsage,
|
||||
String attributeName,
|
||||
Class<A> annotationType,
|
||||
BindingContext context) {
|
||||
return getValue( annotationUsage, attributeName, annotationType, context );
|
||||
}
|
||||
|
||||
public static <A extends Annotation> String getStringOrNull(
|
||||
AnnotationUsage<A> annotationUsage,
|
||||
String attributeName) {
|
||||
return getValueOrNull( annotationUsage, attributeName );
|
||||
}
|
||||
|
||||
public static <A extends Annotation> Identifier getIdentifier(
|
||||
AnnotationUsage<A> annotationUsage,
|
||||
String attributeName,
|
||||
Class<A> 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 <A extends Annotation> 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,A extends Annotation> T getValue(AnnotationUsage<A> ann, String attributeName, Supplier<T> defaultValueSupplier) {
|
||||
if ( ann == null ) {
|
||||
return (T) defaultValueSupplier.get();
|
||||
return defaultValueSupplier.get();
|
||||
}
|
||||
|
||||
return ann.getAttributeValue( attributeName, defaultValueSupplier );
|
||||
|
|
|
@ -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<BatchSize> 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> dynamicInsert = typeMetadata
|
||||
.getClassDetails()
|
||||
.getAnnotationUsage( HibernateAnnotations.DYNAMIC_INSERT );
|
||||
final AnnotationUsage<DynamicUpdate> dynamicUpdate = typeMetadata
|
||||
.getClassDetails()
|
||||
.getAnnotationUsage( HibernateAnnotations.DYNAMIC_UPDATE );
|
||||
|
||||
final List<AnnotationUsage<SQLInsert>> customInserts = typeMetadata
|
||||
.getClassDetails()
|
||||
.getRepeatedAnnotationUsages( HibernateAnnotations.SQL_INSERT );
|
||||
final List<AnnotationUsage<SQLUpdate>> customUpdates = typeMetadata
|
||||
.getClassDetails()
|
||||
.getRepeatedAnnotationUsages( HibernateAnnotations.SQL_UPDATE );
|
||||
final List<AnnotationUsage<SQLDelete>> 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<String,Join> 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<String, Join> extractJoinMap(PersistentClass persistentClass) {
|
||||
final List<Join> joins = persistentClass.getJoins();
|
||||
if ( CollectionHelper.isEmpty( joins ) ) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final HashMap<String, Join> joinMap = CollectionHelper.mapOfSize( joins.size() );
|
||||
joins.forEach( (join) -> joinMap.put( join.getTable().getName(), join ) );
|
||||
return joinMap;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> void applyCustomSql(
|
||||
List<AnnotationUsage<A>> annotationUsages,
|
||||
PersistentClass persistentClass,
|
||||
Map<String,Join> 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<Synchronize> usage = typeMetadata
|
||||
.getClassDetails()
|
||||
.getAnnotationUsage( HibernateAnnotations.SYNCHRONIZE );
|
||||
if ( usage == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// todo : handle Synchronize#logical - for now assume it is logical
|
||||
final List<String> names = usage.getList( "value" );
|
||||
names.forEach( persistentClass::addSynchronizedTable );
|
||||
}
|
||||
|
||||
protected void processSecondaryTables(TableReference primaryTableReference) {
|
||||
TableHelper.bindSecondaryTables(
|
||||
this,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ForeignKey> foreignKeyAnn = BindingHelper.getValue( joinTableAnn, "foreignKey", (AnnotationUsage<ForeignKey>) 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,
|
||||
|
|
|
@ -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 <A extends Annotation> PhysicalTableReference bindPhysicalTable(
|
||||
EntityTypeMetadata type,
|
||||
AnnotationUsage<A> tableAnn,
|
||||
Class<A> 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 <A extends Annotation> PhysicalTable bindExplicitPhysicalTable(
|
||||
EntityTypeMetadata type,
|
||||
AnnotationUsage<A> tableAnn,
|
||||
Class<A> 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 <A extends Annotation> Identifier resolveDatabaseIdentifier(
|
||||
AnnotationUsage<A> annotationUsage,
|
||||
String attributeName,
|
||||
Class<A> 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<Comment> findCommentAnnotation(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SimpleBindingCoordinatorTests {
|
||||
@Test
|
||||
@ServiceRegistry( settingProviders = @SettingProvider(
|
||||
settingName = AvailableSettings.PHYSICAL_NAMING_STRATEGY,
|
||||
provider = CustomNamingStrategyProvider.class
|
||||
) )
|
||||
void testIt(ServiceRegistryScope scope) {
|
||||
public class SimpleBindingCoordinatorTests {
|
||||
@Test
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue