From c5807ee2575105c08a3fb31f5809f1771d73c42e Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 27 May 2024 17:06:14 +0200 Subject: [PATCH] HHH-18139 further integrate legacy identifier generates with new infrastructure - recover ability to use BeanContainer - simplify logic by making full use of Generator.allowAssignedIdentifiers() - various simplifications - deprecate CustomIdGeneratorCreationContext (which was incubating) Signed-off-by: Gavin King --- .../boot/model/internal/EmbeddableBinder.java | 4 +- .../boot/model/internal/EntityBinder.java | 5 +- .../boot/model/internal/GeneratorBinder.java | 375 +++++++++++------- .../boot/model/internal/PropertyBinder.java | 48 ++- .../internal/DefaultPersistEventListener.java | 29 +- .../CustomIdGeneratorCreationContext.java | 7 +- .../org/hibernate/generator/Generator.java | 2 +- .../generator/GeneratorCreationContext.java | 2 + .../main/java/org/hibernate/id/Assigned.java | 23 +- .../org/hibernate/id/ForeignGenerator.java | 66 +-- .../id/IdentifierGeneratorHelper.java | 69 ++++ .../internal/SessionFactoryImpl.java | 4 +- .../java/org/hibernate/mapping/Property.java | 5 + .../org/hibernate/mapping/SimpleValue.java | 18 +- .../entity/AbstractEntityPersister.java | 3 +- ...rnateOrmSpecificAttributesMappingTest.java | 6 + 16 files changed, 378 insertions(+), 288 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java index 63e5ecd5040c..b978732ca82f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java @@ -62,7 +62,7 @@ import static org.hibernate.boot.model.internal.AnnotatedDiscriminatorColumn.DEFAULT_DISCRIMINATOR_COLUMN_NAME; import static org.hibernate.boot.model.internal.AnnotatedDiscriminatorColumn.buildDiscriminatorColumn; -import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation; +import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.getPath; import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId; import static org.hibernate.boot.model.internal.BinderHelper.getRelativePath; @@ -796,7 +796,7 @@ private static void processGeneratedId(MetadataBuildingContext context, Componen final AnnotationUsage generatedValue = property.getAnnotationUsage( GeneratedValue.class ); final String generatorType = generatedValue != null ? generatorType( generatedValue, property.getType().determineRawClass(), context ) - : DEFAULT_ID_GEN_STRATEGY; + : GeneratorBinder.ASSIGNED_GENERATOR_NAME; final String generator = generatedValue != null ? generatedValue.getString( "generator" ) : ""; if ( isGlobalGeneratorNameGlobal( context ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index d489601d3ba8..c95140065ea2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -169,7 +169,6 @@ import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.unqualify; import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; -import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; /** @@ -750,7 +749,7 @@ private static void handleIdGenerator(PropertyData inferredData, MetadataBuildin buildingContext.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( id, inferredData.getAttributeMember(), - DEFAULT_ID_GEN_STRATEGY, + GeneratorBinder.ASSIGNED_GENERATOR_NAME, "", buildingContext ) ); @@ -759,7 +758,7 @@ private static void handleIdGenerator(PropertyData inferredData, MetadataBuildin makeIdGenerator( id, inferredData.getAttributeMember(), - DEFAULT_ID_GEN_STRATEGY, + GeneratorBinder.ASSIGNED_GENERATOR_NAME, "", buildingContext, Collections.emptyMap() diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java index 3a8f0c558c04..35d01341789c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java @@ -7,7 +7,6 @@ package org.hibernate.boot.model.internal; import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.util.HashMap; @@ -15,7 +14,6 @@ import java.util.Properties; import org.hibernate.AnnotationException; -import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.IdGeneratorType; @@ -63,11 +61,11 @@ import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.MemberDetails; -import org.hibernate.mapping.Value; import org.hibernate.resource.beans.container.spi.BeanContainer; import org.hibernate.resource.beans.container.spi.ContainedBean; import org.hibernate.resource.beans.spi.BeanInstanceProducer; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -82,8 +80,7 @@ import static org.hibernate.boot.model.internal.AnnotationHelper.extractParameterMap; import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId; import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal; -import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor; -import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; +import static org.hibernate.resource.beans.internal.Helper.allowExtensionsInCdi; /** * Responsible for configuring and instantiating {@link Generator}s. @@ -92,40 +89,20 @@ */ public class GeneratorBinder { - private static final Logger LOG = CoreLogging.logger( BinderHelper.class ); + private static final Logger LOG = CoreLogging.logger( GeneratorBinder.class ); - /** - * Create an id generator for the given named {@code strategy} using the - * "old" (pre-Hibernate 6) approach. - */ - public static Generator createLegacyIdentifierGenerator( - String strategy, - SimpleValue idValue, - Dialect dialect, - RootClass rootClass, - Map configuration) { - final Generator identifierGenerator = instantiateGenerator( generatorClass( strategy, idValue ) ); - if ( identifierGenerator instanceof Configurable ) { - final Configurable configurable = (Configurable) identifierGenerator; - configurable.configure( idValue.getType(), - collectParameters( idValue, dialect, rootClass, configuration ), - idValue.getServiceRegistry() ); - } - return identifierGenerator; - } - - private static Generator instantiateGenerator(Class generatorClass) { - final Constructor defaultConstructor = getDefaultConstructor( generatorClass ); - if ( defaultConstructor == null ) { - throw new org.hibernate.InstantiationException( "No default constructor for id generator class", generatorClass); - } - try { - return defaultConstructor.newInstance(); - } - catch (Exception e) { - throw new org.hibernate.InstantiationException( "Could not instantiate id generator", generatorClass, e ); - } - } + public static final String ASSIGNED_GENERATOR_NAME = "assigned"; + public static final IdentifierGeneratorCreator ASSIGNED_IDENTIFIER_GENERATOR_CREATOR = + new IdentifierGeneratorCreator() { + @Override + public Generator createGenerator(CustomIdGeneratorCreationContext context) { + return new Assigned( context.getRootClass().getEntityName() ); + } + @Override + public boolean isAssigned() { + return true; + } + }; /** * Interpret an "old" generator strategy name as a {@link Generator} class. @@ -177,12 +154,12 @@ private static Class generatorClass(String strategy, Simple * {@link Configurable#configure(Type, Properties, ServiceRegistry)}. */ public static Properties collectParameters( - SimpleValue simpleValue, + SimpleValue identifierValue, Dialect dialect, RootClass rootClass, Map configuration) { final ConfigurationService configService = - simpleValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry() + identifierValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry() .requireService( ConfigurationService.class ); final Properties params = new Properties(); @@ -196,11 +173,11 @@ public static Properties collectParameters( //init the table here instead of earlier, so that we can get a quoted table name //TODO: would it be better to simply pass the qualified table name, instead of // splitting it up into schema/catalog/table names - final String tableName = simpleValue.getTable().getQuotedName( dialect ); + final String tableName = identifierValue.getTable().getQuotedName( dialect ); params.setProperty( PersistentIdentifierGenerator.TABLE, tableName ); //pass the column name (a generated id almost always has a single column) - final Column column = (Column) simpleValue.getSelectables().get(0); + final Column column = (Column) identifierValue.getSelectables().get(0); final String columnName = column.getQuotedName( dialect ); params.setProperty( PersistentIdentifierGenerator.PK, columnName ); @@ -211,9 +188,9 @@ public static Properties collectParameters( // The table name is not really a good default for subselect entities, // so use the JPA entity name which is short params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, - simpleValue.getTable().isSubselect() + identifierValue.getTable().isSubselect() ? rootClass.getJpaEntityName() - : simpleValue.getTable().getName() ); + : identifierValue.getTable().getName() ); params.setProperty( PersistentIdentifierGenerator.TABLES, identityTablesString( dialect, rootClass ) ); @@ -224,7 +201,7 @@ public static Properties collectParameters( } params.put( IdentifierGenerator.CONTRIBUTOR_NAME, - simpleValue.getBuildingContext().getCurrentContributorName() ); + identifierValue.getBuildingContext().getCurrentContributorName() ); final Map settings = configService.getSettings(); if ( settings.containsKey( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) ) { @@ -272,48 +249,57 @@ public static void makeIdGenerator( MemberDetails idAttributeMember, String generatorType, String generatorName, - MetadataBuildingContext buildingContext, - Map localGenerators) { - LOG.debugf( "#makeIdGenerator(%s, %s, %s, %s, ...)", id, idAttributeMember, generatorType, generatorName ); + MetadataBuildingContext context, + Map localGenerators) { //generator settings - final Map parameters = new HashMap<>(); + final Map configuration = new HashMap<>(); //always settable - parameters.put( PersistentIdentifierGenerator.TABLE, id.getTable().getName() ); + configuration.put( PersistentIdentifierGenerator.TABLE, id.getTable().getName() ); if ( id.getColumnSpan() == 1 ) { - parameters.put( PersistentIdentifierGenerator.PK, id.getColumns().get(0).getName() ); + configuration.put( PersistentIdentifierGenerator.PK, id.getColumns().get(0).getName() ); } // YUCK! but cannot think of a clean way to do this given the string-config based scheme - parameters.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, buildingContext.getObjectNameNormalizer() ); - parameters.put( IdentifierGenerator.GENERATOR_NAME, generatorName ); + configuration.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, context.getObjectNameNormalizer() ); + configuration.put( IdentifierGenerator.GENERATOR_NAME, generatorName ); + + final String generatorStrategy = + determineStrategy( idAttributeMember, generatorType, generatorName, context, localGenerators, configuration ); + setGeneratorCreator( id, configuration, generatorStrategy, beanContainer( context ) ); + } - final String generatorStrategy; + private static String determineStrategy( + MemberDetails idAttributeMember, + String generatorType, + String generatorName, + MetadataBuildingContext context, + Map localGenerators, + Map configuration) { if ( !generatorName.isEmpty() ) { //we have a named generator final IdentifierGeneratorDefinition definition = - makeIdentifierGeneratorDefinition( generatorName, idAttributeMember, localGenerators, buildingContext ); + makeIdentifierGeneratorDefinition( generatorName, idAttributeMember, localGenerators, context ); if ( definition == null ) { throw new AnnotationException( "No id generator was declared with the name '" + generatorName + "' specified by '@GeneratedValue'" + " (define a named generator using '@SequenceGenerator', '@TableGenerator', or '@GenericGenerator')" ); } //This is quite vague in the spec but a generator could override the generator choice - generatorStrategy = + final String generatorStrategy = generatorType == null //yuk! this is a hack not to override 'AUTO' even if generator is set || !definition.getStrategy().equals( "identity" ) ? definition.getStrategy() : generatorType; //checkIfMatchingGenerator(definition, generatorType, generatorName); - parameters.putAll( definition.getParameters() ); + configuration.putAll( definition.getParameters() ); + return generatorStrategy; } else { - generatorStrategy = generatorType; + return generatorType; } - - setGeneratorCreator( id, parameters, generatorStrategy ); } /** @@ -326,18 +312,16 @@ public static void makeIdGenerator( String generatorName, MetadataBuildingContext buildingContext, IdentifierGeneratorDefinition foreignKGeneratorDefinition) { - Map localIdentifiers = null; - if ( foreignKGeneratorDefinition != null ) { - localIdentifiers = new HashMap<>(); - localIdentifiers.put( foreignKGeneratorDefinition.getName(), foreignKGeneratorDefinition ); - } - makeIdGenerator( id, idAttributeMember, generatorType, generatorName, buildingContext, localIdentifiers ); + makeIdGenerator( id, idAttributeMember, generatorType, generatorName, buildingContext, + foreignKGeneratorDefinition != null + ? Map.of( foreignKGeneratorDefinition.getName(), foreignKGeneratorDefinition ) + : null ); } private static IdentifierGeneratorDefinition makeIdentifierGeneratorDefinition( String name, MemberDetails idAttributeMember, - Map localGenerators, + Map localGenerators, MetadataBuildingContext buildingContext) { if ( localGenerators != null ) { final IdentifierGeneratorDefinition result = localGenerators.get( name ); @@ -357,7 +341,7 @@ private static IdentifierGeneratorDefinition makeIdentifierGeneratorDefinition( final AnnotationUsage generatedValue = idAttributeMember.getAnnotationUsage( GeneratedValue.class ); if ( generatedValue == null ) { // this should really never happen, but it's easy to protect against it... - return new IdentifierGeneratorDefinition( DEFAULT_ID_GEN_STRATEGY, DEFAULT_ID_GEN_STRATEGY ); + return new IdentifierGeneratorDefinition(ASSIGNED_GENERATOR_NAME, ASSIGNED_GENERATOR_NAME); } return IdentifierGeneratorDefinition.createImplicit( @@ -409,10 +393,10 @@ static String generatorType( AnnotationUsage generatedValue) { if ( isComponent ) { //a component must not have any generator - return DEFAULT_ID_GEN_STRATEGY; + return ASSIGNED_GENERATOR_NAME; } else { - return generatedValue == null ? DEFAULT_ID_GEN_STRATEGY : generatorType( generatedValue, entityXClass, context ); + return generatedValue == null ? ASSIGNED_GENERATOR_NAME : generatorType( generatedValue, entityXClass, context ); } } @@ -518,7 +502,7 @@ private static void checkGeneratorInterfaces(Class generato static GeneratorCreator generatorCreator( MemberDetails memberDetails, AnnotationUsage annotation, - MetadataBuildingContext buildingContext) { + BeanContainer beanContainer) { final Class annotationType = annotation.getAnnotationType(); final ValueGenerationType generatorAnnotation = annotationType.getAnnotation( ValueGenerationType.class ); if ( generatorAnnotation == null ) { @@ -532,9 +516,9 @@ static GeneratorCreator generatorCreator( annotation, memberDetails, annotationType, + creationContext, GeneratorCreationContext.class, - generatorClass, - creationContext + generatorClass ); callInitialize( annotation, memberDetails, creationContext, generator ); checkVersionGenerationAlways( memberDetails, generator ); @@ -545,6 +529,7 @@ static GeneratorCreator generatorCreator( static IdentifierGeneratorCreator identifierGeneratorCreator( MemberDetails idAttributeMember, AnnotationUsage annotation, + SimpleValue identifierValue, BeanContainer beanContainer) { final Class annotationType = annotation.getAnnotationType(); final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class ); @@ -557,21 +542,31 @@ static IdentifierGeneratorCreator identifierGeneratorCreator( annotation, beanContainer, creationContext, + CustomIdGeneratorCreationContext.class, generatorClass, idAttributeMember, annotationType ); callInitialize( annotation, idAttributeMember, creationContext, generator ); - callConfigure( creationContext, generator ); + callConfigure( creationContext, generator, emptyMap(), identifierValue ); checkIdGeneratorTiming( annotationType, generator ); return generator; }; } - private static Generator instantiateGenerator( + /** + * Instantiate a {@link Generator}, using the given {@link BeanContainer} if any, + * for the case where the generator was specified using a generator annotation. + * + * @param annotation the generator annotation + * @param beanContainer an optional {@code BeanContainer} + * @param generatorClass a class which implements {@code Generator} + */ + private static Generator instantiateGenerator( AnnotationUsage annotation, BeanContainer beanContainer, - CustomIdGeneratorCreationContext creationContext, + C creationContext, + Class creationContextClass, Class generatorClass, MemberDetails idAttributeMember, Class annotationType) { @@ -580,6 +575,7 @@ private static Generator instantiateGenerator( annotation, beanContainer, creationContext, + creationContextClass, generatorClass, idAttributeMember, annotationType @@ -590,17 +586,26 @@ private static Generator instantiateGenerator( annotation, idAttributeMember, annotationType, - CustomIdGeneratorCreationContext.class, - generatorClass, - creationContext + creationContext, + creationContextClass, + generatorClass ); } } - private static Generator instantiateGeneratorAsBean( + /** + * Instantiate a {@link Generator}, using the given {@link BeanContainer}, + * for the case where the generator was specified using a generator annotation. + * + * @param annotation the generator annotation + * @param beanContainer an optional {@code BeanContainer} + * @param generatorClass a class which implements {@code Generator} + */ + private static Generator instantiateGeneratorAsBean( AnnotationUsage annotation, BeanContainer beanContainer, - CustomIdGeneratorCreationContext creationContext, + C creationContext, + Class creationContextClass, Class generatorClass, MemberDetails idAttributeMember, Class annotationType) { @@ -623,47 +628,125 @@ public B produceBeanInstance(Class beanType) { annotation, idAttributeMember, annotationType, - CustomIdGeneratorCreationContext.class, - generatorClass, - creationContext + creationContext, + creationContextClass, + generatorClass ); } @Override public B produceBeanInstance(String name, Class beanType) { return produceBeanInstance( beanType ); } - } ).getBeanInstance(); + } ) + .getBeanInstance(); + } + + /** + * Instantiate a {@link Generator}, using the given {@link BeanContainer}, + * for the case where no generator annotation is available. + * + * @param beanContainer an optional {@code BeanContainer} + * @param generatorClass a class which implements {@code Generator} + */ + private static Generator instantiateGeneratorAsBean( + BeanContainer beanContainer, + Class generatorClass) { + return beanContainer.getBean( generatorClass, + new BeanContainer.LifecycleOptions() { + @Override + public boolean canUseCachedReferences() { + return false; + } + @Override + public boolean useJpaCompliantCreation() { + return true; + } + }, + new BeanInstanceProducer() { + @SuppressWarnings( "unchecked" ) + @Override + public B produceBeanInstance(Class beanType) { + return (B) instantiateGeneratorViaDefaultConstructor( generatorClass ); + } + @Override + public B produceBeanInstance(String name, Class beanType) { + return produceBeanInstance( beanType ); + } + } ) + .getBeanInstance(); } + /** + * Instantiate a {@link Generator} by calling an appropriate constructor, + * for the case where the generator was specified using a generator annotation. + * We look for three possible signatures: + *
    + *
  1. {@code (Annotation, Member, GeneratorCreationContext)}
  2. + *
  3. {@code (Annotation)}
  4. + *
  5. {@code ()}
  6. + *
+ * where {@code Annotation} is the generator annotation type. + * + * @param annotation the generator annotation + * @param generatorClass a class which implements {@code Generator} + */ private static G instantiateGenerator( AnnotationUsage annotation, MemberDetails memberDetails, Class annotationType, + C creationContext, Class contextClass, - Class generatorClass, - C creationContext) { + Class generatorClass) { try { try { - return generatorClass - .getConstructor( annotationType, Member.class, contextClass ) + return generatorClass.getConstructor( annotationType, Member.class, contextClass ) .newInstance( annotation.toAnnotation(), memberDetails.toJavaMember(), creationContext); } catch (NoSuchMethodException ignore) { try { - return generatorClass - .getConstructor( annotationType ) + return generatorClass.getConstructor( annotationType ) .newInstance( annotation.toAnnotation() ); } catch (NoSuchMethodException i) { - return generatorClass.newInstance(); + return instantiateGeneratorViaDefaultConstructor( generatorClass ); } } } catch (InvocationTargetException | InstantiationException | IllegalAccessException | IllegalArgumentException e) { - throw new HibernateException( - "Could not instantiate generator of type '" + generatorClass.getName() + "'", - e - ); + throw new org.hibernate.InstantiationException( "Could not instantiate id generator", generatorClass, e ); + } + } + + /** + * Instantiate a {@link Generator}, using the given {@link BeanContainer} if any, + * or by calling the default constructor otherwise. + * + * @param beanContainer an optional {@code BeanContainer} + * @param generatorClass a class which implements {@code Generator} + */ + private static Generator instantiateGenerator( + BeanContainer beanContainer, + Class generatorClass) { + if ( beanContainer != null ) { + return instantiateGeneratorAsBean( beanContainer, generatorClass ); + } + else { + return instantiateGeneratorViaDefaultConstructor( generatorClass ); + } + } + + /** + * Instantiate a {@link Generator} by calling the default constructor. + */ + private static G instantiateGeneratorViaDefaultConstructor(Class generatorClass) { + try { + return generatorClass.getDeclaredConstructor().newInstance(); + } + catch (NoSuchMethodException e) { + throw new org.hibernate.InstantiationException( "No appropriate constructor for id generator class", generatorClass); + } + catch (Exception e) { + throw new org.hibernate.InstantiationException( "Could not instantiate id generator", generatorClass, e ); } } @@ -697,16 +780,25 @@ private static void checkVersionGenerationAlways(MemberDetails property, Generat } } - private static void callConfigure(GeneratorCreationContext creationContext, Generator generator) { + /** + * If the given {@link Generator} also implements {@link Configurable}, + * call its {@link Configurable#configure(Type, Properties, ServiceRegistry) + * configure()} method. + */ + private static void callConfigure( + GeneratorCreationContext creationContext, + Generator generator, + Map configuration, + SimpleValue identifierValue) { if ( generator instanceof Configurable ) { - final Value value = creationContext.getProperty().getValue(); - Properties parameters = collectParameters( - (SimpleValue) value, + final Configurable configurable = (Configurable) generator; + final Properties parameters = collectParameters( + identifierValue, creationContext.getDatabase().getDialect(), - creationContext.getPersistentClass().getRootClass(), - emptyMap() + creationContext.getRootClass(), + configuration ); - ( (Configurable) generator ).configure( value.getType(), parameters, creationContext.getServiceRegistry() ); + configurable.configure( identifierValue.getType(), parameters, creationContext.getServiceRegistry() ); } } @@ -734,13 +826,14 @@ static void createIdGenerator( final String generatorName = generatedValue == null ? "" : generatedValue.getString( "generator" ); if ( isGlobalGeneratorNameGlobal( context ) ) { buildGenerators( idAttributeMember, context ); - context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( - idValue, - idAttributeMember, - generatorType, - generatorName, - context - ) ); + context.getMetadataCollector() + .addSecondPass( new IdGeneratorResolverSecondPass( + idValue, + idAttributeMember, + generatorType, + generatorName, + context + ) ); } else { //clone classGenerator and override with local values @@ -762,7 +855,7 @@ public static void makeIdGenerator( MetadataBuildingContext buildingContext) { if ( definition != null ) { - final Map params = new HashMap<>(); + final Map configuration = new HashMap<>(); // see if the specified generator name matches a registered final IdentifierGeneratorDefinition generatorDef = @@ -770,47 +863,55 @@ public static void makeIdGenerator( final String generatorStrategy; if ( generatorDef != null ) { generatorStrategy = generatorDef.getStrategy(); - params.putAll( generatorDef.getParameters() ); + configuration.putAll( generatorDef.getParameters() ); } else { generatorStrategy = definition.getStrategy(); } // YUCK! but cannot think of a clean way to do this given the string-config based scheme - params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, + configuration.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, buildingContext.getObjectNameNormalizer() ); - params.putAll( definition.getParameters() ); + configuration.putAll( definition.getParameters() ); - setGeneratorCreator( identifierValue, params, generatorStrategy ); + setGeneratorCreator( identifierValue, configuration, generatorStrategy, beanContainer( buildingContext ) ); } } + /** + * Obtain a {@link BeanContainer} to be used for instantiating generators. + */ + static BeanContainer beanContainer(MetadataBuildingContext buildingContext) { + final ServiceRegistry serviceRegistry = buildingContext.getBootstrapContext().getServiceRegistry(); + return allowExtensionsInCdi( serviceRegistry ) + ? serviceRegistry.requireService( ManagedBeanRegistry.class ).getBeanContainer() + : null; + } + + /** + * Set up the {@link IdentifierGeneratorCreator} for a case where there is no + * generator annotation. + */ private static void setGeneratorCreator( SimpleValue identifierValue, - Map parameters, - String generatorStrategy) { - identifierValue.setCustomIdGeneratorCreator( new IdentifierGeneratorCreator() { - @Override - public Generator createGenerator(CustomIdGeneratorCreationContext context) { - final Generator generator = - createLegacyIdentifierGenerator( - generatorStrategy, - identifierValue, - context.getDatabase().getDialect(), - context.getRootClass(), - parameters - ); - if ( generator instanceof IdentityGenerator) { + Map configuration, + String generatorStrategy, + BeanContainer beanContainer) { + if ( ASSIGNED_GENERATOR_NAME.equals( generatorStrategy ) + || Assigned.class.getName().equals( generatorStrategy ) ) { + identifierValue.setCustomIdGeneratorCreator( ASSIGNED_IDENTIFIER_GENERATOR_CREATOR ); + } + else { + identifierValue.setCustomIdGeneratorCreator( creationContext -> { + final Generator identifierGenerator = + instantiateGenerator( beanContainer, generatorClass( generatorStrategy, identifierValue ) ); + callConfigure( creationContext, identifierGenerator, configuration, identifierValue ); + if ( identifierGenerator instanceof IdentityGenerator) { identifierValue.setColumnToIdentity(); } - return generator; - } - - @Override - public boolean isAssigned() { - return DEFAULT_ID_GEN_STRATEGY.equals( generatorStrategy ); - } - } ); + return identifierGenerator; + } ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java index 887252763d29..4ca5a734062c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java @@ -7,6 +7,7 @@ package org.hibernate.boot.model.internal; import java.lang.annotation.Annotation; +import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -36,7 +37,10 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.engine.OptimisticLockStyle; -import org.hibernate.id.ForeignGenerator; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.generator.BeforeExecutionGenerator; +import org.hibernate.generator.EventType; +import org.hibernate.generator.EventTypeSets; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Component; @@ -63,8 +67,6 @@ import org.hibernate.usertype.CompositeUserType; import org.hibernate.resource.beans.container.spi.BeanContainer; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; -import org.hibernate.service.ServiceRegistry; import org.jboss.logging.Logger; import jakarta.persistence.Basic; @@ -95,17 +97,17 @@ import static org.hibernate.boot.model.internal.EmbeddableBinder.createCompositeBinder; import static org.hibernate.boot.model.internal.EmbeddableBinder.createEmbeddable; import static org.hibernate.boot.model.internal.EmbeddableBinder.isEmbedded; +import static org.hibernate.boot.model.internal.GeneratorBinder.beanContainer; import static org.hibernate.boot.model.internal.GeneratorBinder.createIdGenerator; -import static org.hibernate.boot.model.internal.GeneratorBinder.createLegacyIdentifierGenerator; import static org.hibernate.boot.model.internal.GeneratorBinder.generatorCreator; import static org.hibernate.boot.model.internal.GeneratorBinder.identifierGeneratorCreator; import static org.hibernate.boot.model.internal.TimeZoneStorageHelper.resolveTimeZoneStorageCompositeUserType; import static org.hibernate.boot.model.internal.ToOneBinder.bindManyToOne; import static org.hibernate.boot.model.internal.ToOneBinder.bindOneToOne; import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.hibernate.id.IdentifierGeneratorHelper.getForeignId; import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.collections.CollectionHelper.combine; -import static org.hibernate.resource.beans.internal.Helper.allowExtensionsInCdi; /** * A stateful binder responsible for creating {@link Property} objects. @@ -442,9 +444,10 @@ private void handleValueGeneration(Property property) { * Returns the value generation strategy for the given property, if any. */ private GeneratorCreator getValueGenerationFromAnnotations(MemberDetails property) { + final BeanContainer beanContainer = beanContainer( buildingContext ); GeneratorCreator creator = null; for ( AnnotationUsage usage : property.getAllAnnotationUsages() ) { - final GeneratorCreator candidate = generatorCreator( property, usage, buildingContext ); + final GeneratorCreator candidate = generatorCreator( property, usage, beanContainer ); if ( candidate != null ) { if ( creator != null ) { throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) @@ -1185,13 +1188,26 @@ private static void handleGeneratorsForOverriddenId( final SimpleValue idValue = (SimpleValue) propertyBinder.getValue(); final RootClass rootClass = propertyHolder.getPersistentClass().getRootClass(); final String propertyName = mapsIdProperty.getPropertyName(); + final String entityName = rootClass.getEntityName(); idValue.setCustomIdGeneratorCreator( creationContext -> - createLegacyIdentifierGenerator( "foreign", - idValue, - creationContext.getDatabase().getDialect(), - rootClass, - Map.of( ForeignGenerator.PROPERTY, propertyName ) - ) + new BeforeExecutionGenerator() { + @Override + public Object generate( + SharedSessionContractImplementor session, + Object owner, + Object currentValue, + EventType eventType) { + return getForeignId( entityName, propertyName, session, owner ); + } + @Override + public EnumSet getEventTypes() { + return EventTypeSets.INSERT_ONLY; + } + @Override + public boolean allowAssignedIdentifiers() { + return true; + } + } ); } @@ -1435,12 +1451,8 @@ private static void processId( } if ( !idGeneratorAnnotations.isEmpty() ) { final AnnotationUsage annotation = idGeneratorAnnotations.get(0); - final ServiceRegistry serviceRegistry = context.getBootstrapContext().getServiceRegistry(); - final BeanContainer beanContainer = - allowExtensionsInCdi( serviceRegistry ) - ? serviceRegistry.requireService( ManagedBeanRegistry.class ).getBeanContainer() - : null; - idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idAttributeMember, annotation, beanContainer ) ); + idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idAttributeMember, annotation, + idValue, beanContainer( context ) ) ); } else if ( !generatorAnnotations.isEmpty() ) { // idValue.setCustomGeneratorCreator( generatorCreator( idAttributeMember, generatorAnnotation ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java index d051f57bf77b..78711f9d6821 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java @@ -17,7 +17,6 @@ import org.hibernate.event.spi.PersistContext; import org.hibernate.event.spi.PersistEvent; import org.hibernate.event.spi.PersistEventListener; -import org.hibernate.id.ForeignGenerator; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; @@ -82,7 +81,7 @@ private void persist(PersistEvent event, PersistContext createCache, Object enti final EventSource source = event.getSession(); final EntityEntry entityEntry = source.getPersistenceContextInternal().getEntry( entity ); final String entityName = entityName( event, entity, entityEntry ); - switch ( entityState( event, entity, entityName, entityEntry ) ) { + switch ( getEntityState( entity, entityName, entityEntry, source, true ) ) { case DETACHED: throw new PersistentObjectException( "detached entity passed to persist: " + EventUtil.getLoggableName( event.getEntityName(), entity) ); @@ -107,32 +106,6 @@ private void persist(PersistEvent event, PersistContext createCache, Object enti } } - private static EntityState entityState(PersistEvent event, Object entity, String entityName, EntityEntry entityEntry) { - final EventSource source = event.getSession(); - EntityState entityState = getEntityState( entity, entityName, entityEntry, source, true ); - if ( entityState == EntityState.DETACHED ) { - // JPA 2, in its version of a "foreign generated", allows the id attribute value - // to be manually set by the user, even though this manual value is irrelevant. - // The issue is that this causes problems with the Hibernate unsaved-value strategy - // which comes into play here in determining detached/transient state. - // - // Detect if we have this situation and if so null out the id value and calculate the - // entity state again. - - // NOTE: entityEntry must be null to get here, so we cannot use any of its values - final EntityPersister persister = event.getFactory().getMappingMetamodel() - .getEntityDescriptor( entityName ); - if ( persister.getGenerator() instanceof ForeignGenerator ) { - if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) { - LOG.debug( "Resetting entity id attribute to null for foreign generator" ); - } - persister.setIdentifier( entity, null, source ); - entityState = getEntityState( entity, entityName, entityEntry, source, true ); - } - } - return entityState; - } - private static String entityName(PersistEvent event, Object entity, EntityEntry entityEntry) { if ( event.getEntityName() != null ) { return event.getEntityName(); diff --git a/hibernate-core/src/main/java/org/hibernate/generator/CustomIdGeneratorCreationContext.java b/hibernate-core/src/main/java/org/hibernate/generator/CustomIdGeneratorCreationContext.java index 7fd2fecb0489..9cfafa9d9396 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/CustomIdGeneratorCreationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/CustomIdGeneratorCreationContext.java @@ -7,13 +7,8 @@ package org.hibernate.generator; import org.hibernate.Incubating; -import org.hibernate.mapping.RootClass; @Incubating +@Deprecated(since = "7.0", forRemoval = true) public interface CustomIdGeneratorCreationContext extends GeneratorCreationContext { - RootClass getRootClass(); - - // we could add these if it helps integrate old infrastructure -// Properties getParameters(); -// SqlStringGenerationContext getSqlStringGenerationContext(); } diff --git a/hibernate-core/src/main/java/org/hibernate/generator/Generator.java b/hibernate-core/src/main/java/org/hibernate/generator/Generator.java index b0f91efe1675..31f86b18bd9f 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/Generator.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/Generator.java @@ -138,7 +138,7 @@ default boolean generatedOnExecution(Object entity, SharedSessionContractImpleme * values to be used as identifiers and falling back to generated values by default. * * @return {@code true} if this generator allows pre-assigned identifier values, - * {@code false} otherwise (default). + * {@code false} otherwise (default). * * @since 6.5 */ diff --git a/hibernate-core/src/main/java/org/hibernate/generator/GeneratorCreationContext.java b/hibernate-core/src/main/java/org/hibernate/generator/GeneratorCreationContext.java index 094f0c1e2c9b..6947df8692b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/GeneratorCreationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/GeneratorCreationContext.java @@ -10,6 +10,7 @@ import org.hibernate.boot.model.relational.Database; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.mapping.RootClass; import org.hibernate.service.ServiceRegistry; @Incubating @@ -21,6 +22,7 @@ public interface GeneratorCreationContext { String getDefaultSchema(); PersistentClass getPersistentClass(); + RootClass getRootClass(); Property getProperty(); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java index c0272dec4c3d..a9fce873322b 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java +++ b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java @@ -6,13 +6,8 @@ */ package org.hibernate.id; -import java.util.Properties; - import org.hibernate.HibernateException; -import org.hibernate.MappingException; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.type.Type; /** * An {@link IdentifierGenerator} that returns the current identifier assigned @@ -23,28 +18,24 @@ * @implNote This also implements the {@code assigned} generation type in {@code hbm.xml} mappings. */ public class Assigned implements IdentifierGenerator { - private String entityName; + private final String entityName; + + public Assigned(String entityName) { + this.entityName = entityName; + } @Override public boolean allowAssignedIdentifiers() { return true; } - public Object generate(SharedSessionContractImplementor session, Object obj) throws HibernateException { + public Object generate(SharedSessionContractImplementor session, Object owner) throws HibernateException { //TODO: cache the persister, this shows up in yourkit - final Object id = session.getEntityPersister( entityName, obj ).getIdentifier( obj, session ); + final Object id = session.getEntityPersister( entityName, owner ).getIdentifier( owner, session ); if ( id == null ) { throw new IdentifierGenerationException( "Identifier for entity '" + entityName + "' must be manually assigned before making the entity persistent" ); } return id; } - - @Override - public void configure(Type type, Properties parameters, ServiceRegistry serviceRegistry) throws MappingException { - entityName = parameters.getProperty( ENTITY_NAME ); - if ( entityName == null ) { - throw new MappingException("no entity name"); - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java index af966aaf9aa6..901e13ed30e0 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java @@ -9,18 +9,11 @@ import java.util.Properties; import org.hibernate.MappingException; -import org.hibernate.TransientObjectException; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.persister.entity.EntityPersister; import org.hibernate.service.ServiceRegistry; -import org.hibernate.type.EntityType; import org.hibernate.type.Type; -import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved; -import static org.hibernate.id.IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR; -import static org.hibernate.internal.CoreLogging.messageLogger; -import static org.hibernate.spi.NavigablePath.IDENTIFIER_MAPPER_PROPERTY; +import static org.hibernate.id.IdentifierGeneratorHelper.getForeignId; /** * The legacy id generator named {@code foreign}. @@ -36,7 +29,6 @@ */ @Deprecated(since = "6", forRemoval = true) public class ForeignGenerator implements IdentifierGenerator { - private static final CoreMessageLogger LOG = messageLogger( ForeignGenerator.class ); /** * The parameter which specifies the property holding a reference to the associated object. @@ -86,57 +78,11 @@ public void configure(Type type, Properties parameters, ServiceRegistry serviceR @Override public Object generate(SharedSessionContractImplementor sessionImplementor, Object object) { - final EntityPersister entityDescriptor = - sessionImplementor.getFactory().getMappingMetamodel() - .getEntityDescriptor( entityName ); - final Object associatedObject = entityDescriptor.getPropertyValue( object, propertyName ); - if ( associatedObject == null ) { - throw new IdentifierGenerationException( - "attempted to assign id from null one-to-one property [" + getRole() + "]" - ); - } - - final EntityType foreignValueSourceType; - final Type propertyType = entityDescriptor.getPropertyType( propertyName ); - if ( propertyType.isEntityType() ) { - // the normal case - foreignValueSourceType = (EntityType) propertyType; - } - else { - // try identifier mapper - foreignValueSourceType = (EntityType) - entityDescriptor.getPropertyType( IDENTIFIER_MAPPER_PROPERTY + "." + propertyName ); - } - - Object id; - final String associatedEntityName = foreignValueSourceType.getAssociatedEntityName(); - try { - id = getEntityIdentifierIfNotUnsaved( associatedEntityName, associatedObject, sessionImplementor ); - } - catch (TransientObjectException toe) { - if ( LOG.isDebugEnabled() ) { - LOG.debugf( - "ForeignGenerator detected a transient entity [%s]", - associatedEntityName - ); - } - if ( sessionImplementor.isSessionImplementor() ) { - id = sessionImplementor.asSessionImplementor().save( associatedEntityName, associatedObject ); - } - else if ( sessionImplementor.isStatelessSession() ) { - id = sessionImplementor.asStatelessSession().insert( associatedEntityName, associatedObject ); - } - else { - throw new IdentifierGenerationException("sessionImplementor is neither Session nor StatelessSession"); - } - } + return getForeignId( entityName, propertyName, sessionImplementor, object ); + } - if ( sessionImplementor.isSessionImplementor() - && sessionImplementor.asSessionImplementor().contains( entityName, object ) ) { - //abort the save (the object is already saved by a circular cascade) - return SHORT_CIRCUIT_INDICATOR; - //throw new IdentifierGenerationException("save associated object first, or disable cascade for inverse association"); - } - return id; + @Override + public boolean allowAssignedIdentifiers() { + return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java index 063127facff9..f4a76d084f21 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java @@ -18,7 +18,9 @@ import org.hibernate.HibernateException; import org.hibernate.Internal; +import org.hibernate.TransientObjectException; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.generator.values.internal.GeneratedValuesHelper; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; @@ -26,8 +28,14 @@ import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SqlTypedMapping; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.type.EntityType; +import org.hibernate.type.Type; import org.hibernate.type.descriptor.WrapperOptions; +import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved; +import static org.hibernate.spi.NavigablePath.IDENTIFIER_MAPPER_PROPERTY; + /** * Factory and helper methods for {@link IdentifierGenerator} framework. * @@ -188,6 +196,67 @@ else if ( holder.getClass() == BigDecimalHolder.class ) { throw new IdentifierGenerationException( "Unknown IntegralDataTypeHolder impl [" + holder + "]" ); } + public static Object getForeignId( + String entityName, String propertyName, SharedSessionContractImplementor sessionImplementor, Object object) { + final EntityPersister entityDescriptor = + sessionImplementor.getFactory().getMappingMetamodel() + .getEntityDescriptor( entityName ); + if ( sessionImplementor.isSessionImplementor() + && sessionImplementor.asSessionImplementor().contains( entityName, object ) ) { + //abort the save (the object is already saved by a circular cascade) + return SHORT_CIRCUIT_INDICATOR; + //throw new IdentifierGenerationException("save associated object first, or disable cascade for inverse association"); + } + else { + return identifier( sessionImplementor, entityType( propertyName, entityDescriptor ), + associatedEntity( entityName, propertyName, object, entityDescriptor ) ); + } + } + + private static Object associatedEntity( + String entityName, String propertyName, Object object, EntityPersister entityDescriptor) { + final Object associatedObject = entityDescriptor.getPropertyValue( object, propertyName ); + if ( associatedObject == null ) { + throw new IdentifierGenerationException( "Could not assign id from null association '" + propertyName + + "' of entity '" + entityName + "'" ); + } + return associatedObject; + } + + private static Object identifier( + SharedSessionContractImplementor sessionImplementor, + EntityType foreignValueSourceType, + Object associatedEntity) { + final String associatedEntityName = foreignValueSourceType.getAssociatedEntityName(); + try { + return getEntityIdentifierIfNotUnsaved( associatedEntityName, associatedEntity, sessionImplementor ); + } + catch (TransientObjectException toe) { + if ( sessionImplementor.isSessionImplementor() ) { + return sessionImplementor.asSessionImplementor().save( associatedEntityName, associatedEntity ); + } + else if ( sessionImplementor.isStatelessSession() ) { + return sessionImplementor.asStatelessSession().insert( associatedEntityName, associatedEntity ); + } + else { + throw new IdentifierGenerationException("sessionImplementor is neither Session nor StatelessSession"); + } + } + } + + private static EntityType entityType(String propertyName, EntityPersister entityDescriptor) { + final Type propertyType = entityDescriptor.getPropertyType( propertyName ); + if ( propertyType.isEntityType() ) { + // the normal case + return (EntityType) propertyType; + } + else { + // try identifier mapper + final String mapperPropertyName = IDENTIFIER_MAPPER_PROPERTY + "." + propertyName; + return (EntityType) entityDescriptor.getPropertyType( mapperPropertyName ); + } + } + @Internal public static class BasicHolder implements IntegralDataTypeHolder { private final Class exactType; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index cd4f3c46adc6..12520478e07b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -468,7 +468,7 @@ private static Map createGenerators( final Map generators = new HashMap<>(); for ( PersistentClass model : bootMetamodel.getEntityBindings() ) { if ( !model.isInherited() ) { - KeyValue id = model.getIdentifier(); + final KeyValue id = model.getIdentifier(); final Generator generator = id.createGenerator( dialect, (RootClass) model ); if ( generator instanceof Configurable ) { final Configurable identifierGenerator = (Configurable) generator; @@ -476,7 +476,7 @@ private static Map createGenerators( } //TODO: this isn't a great place to do this if ( generator.allowAssignedIdentifiers() && id instanceof SimpleValue ) { - SimpleValue simpleValue = (SimpleValue) id; + final SimpleValue simpleValue = (SimpleValue) id; if ( simpleValue.getNullValue() == null ) { simpleValue.setNullValue( "undefined" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 55bf308400e8..4de1e16ccddc 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -534,6 +534,11 @@ public PersistentClass getPersistentClass() { return persistentClass; } + @Override + public RootClass getRootClass() { + return persistentClass.getRootClass(); + } + @Override public Property getProperty() { return Property.this; diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index 3f777f0ab02c..df08beb17e09 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -37,7 +37,6 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.Mapping; import org.hibernate.generator.Generator; -import org.hibernate.id.Assigned; import org.hibernate.generator.CustomIdGeneratorCreationContext; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; @@ -64,6 +63,8 @@ import static java.lang.Boolean.parseBoolean; import static org.hibernate.boot.model.convert.spi.ConverterDescriptor.TYPE_NAME_PREFIX; +import static org.hibernate.boot.model.internal.GeneratorBinder.ASSIGNED_GENERATOR_NAME; +import static org.hibernate.boot.model.internal.GeneratorBinder.ASSIGNED_IDENTIFIER_GENERATOR_CREATOR; import static org.hibernate.internal.util.collections.ArrayHelper.toBooleanArray; /** @@ -75,7 +76,8 @@ public abstract class SimpleValue implements KeyValue { private static final CoreMessageLogger log = CoreLogging.messageLogger( SimpleValue.class ); - public static final String DEFAULT_ID_GEN_STRATEGY = "assigned"; + @Deprecated(since = "7.0", forRemoval = true) + public static final String DEFAULT_ID_GEN_STRATEGY = ASSIGNED_GENERATOR_NAME; private final MetadataBuildingContext buildingContext; private final MetadataImplementor metadata; @@ -103,17 +105,7 @@ public abstract class SimpleValue implements KeyValue { private ConverterDescriptor attributeConverterDescriptor; private Type type; - private IdentifierGeneratorCreator customIdGeneratorCreator = new IdentifierGeneratorCreator() { - @Override - public Generator createGenerator(CustomIdGeneratorCreationContext context) { - return new Assigned(); - } - - @Override - public boolean isAssigned() { - return true; - } - }; + private IdentifierGeneratorCreator customIdGeneratorCreator = ASSIGNED_IDENTIFIER_GENERATOR_CREATOR; private Generator generator; public SimpleValue(MetadataBuildingContext buildingContext) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 6b8da061777d..8c536c3b308f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -112,7 +112,6 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.id.Assigned; import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; -import org.hibernate.id.ForeignGenerator; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.OptimizableGenerator; import org.hibernate.id.PostInsertIdentityPersister; @@ -4148,7 +4147,7 @@ public Boolean isTransient(Object entity, SharedSessionContractImplementor sessi } } final Generator identifierGenerator = getGenerator(); - if ( identifierGenerator != null && !( identifierGenerator instanceof ForeignGenerator ) ) { + if ( identifierGenerator != null ) { final Boolean unsaved = identifierMapping.getUnsavedStrategy().isUnsaved( id ); if ( unsaved != null && !unsaved ) { throw new PropertyValueException( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HibernateOrmSpecificAttributesMappingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HibernateOrmSpecificAttributesMappingTest.java index a8c45bce7c5f..87ff3dd16ea0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HibernateOrmSpecificAttributesMappingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HibernateOrmSpecificAttributesMappingTest.java @@ -22,6 +22,7 @@ import org.hibernate.mapping.GeneratorCreator; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.mapping.RootClass; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.SqlTypes; import org.hibernate.usertype.UserTypeSupport; @@ -161,6 +162,11 @@ public PersistentClass getPersistentClass() { return tenantId.getPersistentClass(); } + @Override + public RootClass getRootClass() { + return tenantId.getPersistentClass().getRootClass(); + } + @Override public Property getProperty() { return tenantId;