HHH-15789 allow any InMemoryGenerator to generate ids

This commit is contained in:
Gavin 2022-11-30 21:30:45 +01:00 committed by Gavin King
parent 7f72696fff
commit 26e7393775
47 changed files with 763 additions and 560 deletions

View File

@ -6,7 +6,7 @@
*/
package org.hibernate.annotations;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.tuple.InMemoryGenerator;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
@ -74,12 +74,11 @@ public @interface GenericGenerator {
*/
String name();
/**
* The type of identifier generator, a class implementing
* {@link org.hibernate.id.IdentifierGenerator}.
* The type of identifier generator, a class implementing {@link InMemoryGenerator}.
*
* @since 6.2
*/
Class<? extends IdentifierGenerator> type() default IdentifierGenerator.class;
Class<? extends InMemoryGenerator> type() default InMemoryGenerator.class;
/**
* The type of identifier generator, the name of either:
* <ul>

View File

@ -11,6 +11,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.tuple.InMemoryGenerator;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -63,8 +64,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface IdGeneratorType {
/**
* A class that implements {@link IdentifierGenerator} and has a
* constructor with the signature:
* A class that implements {@link InMemoryGenerator} and has a constructor
* with the signature:
* <pre>{@code
* public GeneratorType(AnnotationType config, Member idMember,
* CustomIdGeneratorCreationContext creationContext)
@ -73,5 +74,5 @@ public @interface IdGeneratorType {
* {@code IdentifierGenerator}, and {@code AnnotationType} is the
* annotation type to which this annotation was applied.
*/
Class<? extends IdentifierGenerator> value();
Class<? extends InMemoryGenerator> value();
}

View File

@ -46,6 +46,7 @@ import org.hibernate.boot.model.naming.ImplicitIndexNameSource;
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
@ -102,6 +103,7 @@ import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration;
@ -2314,13 +2316,15 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
// It was done this way in the old code too, so no "regression" here; but
// it could be done better
try {
final IdentifierGenerator ig = identifierValueBinding.createIdentifierGenerator(
final InMemoryGenerator generator = identifierValueBinding.createIdentifierGenerator(
bootstrapContext.getIdentifierGeneratorFactory(),
dialect,
entityBinding
);
ig.registerExportables( getDatabase() );
if ( generator instanceof ExportableProducer ) {
( (ExportableProducer) generator ).registerExportables( getDatabase() );
}
}
catch (MappingException e) {
// ignore this for now. The reasoning being "non-reflective" binding as needed

View File

@ -7,10 +7,20 @@
package org.hibernate.boot.model;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Index;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.UniqueConstraint;
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.collections.CollectionHelper;
import static java.util.Collections.emptyMap;
@ -74,6 +84,171 @@ public class IdentifierGeneratorDefinition implements Serializable {
return parameters;
}
@Internal
public static IdentifierGeneratorDefinition createImplicit(
String name,
Class<?> idType,
String generatorName,
IdGeneratorStrategyInterpreter generationInterpreter,
GenerationType generationType) {
// If we were unable to locate an actual matching named generator assume
// a sequence/table of the given name, make one based on GenerationType.
if ( generationType == null) {
return buildSequenceGeneratorDefinition( name, generationInterpreter );
}
final String strategyName;
switch ( generationType ) {
case SEQUENCE:
return buildSequenceGeneratorDefinition( name, generationInterpreter );
case TABLE:
return buildTableGeneratorDefinition( name, generationInterpreter );
// really AUTO and IDENTITY work the same in this respect, aside from the actual strategy name
case IDENTITY:
strategyName = "identity";
break;
case AUTO:
strategyName = generationInterpreter.determineGeneratorName(
generationType,
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
@Override
public Class<?> getIdType() {
return idType;
}
@Override
public String getGeneratedValueGeneratorName() {
return generatorName;
}
}
);
break;
default:
throw new AssertionFailure( "unknown generator type: " + generationType );
}
return new IdentifierGeneratorDefinition(
name,
strategyName,
Collections.singletonMap( IdentifierGenerator.GENERATOR_NAME, name )
);
}
private static IdentifierGeneratorDefinition buildTableGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretTableGenerator(
new TableGenerator() {
@Override
public String name() {
return name;
}
@Override
public String table() {
return "";
}
@Override
public int initialValue() {
return 0;
}
@Override
public int allocationSize() {
return 50;
}
@Override
public String catalog() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public String pkColumnName() {
return "";
}
@Override
public String valueColumnName() {
return "";
}
@Override
public String pkColumnValue() {
return "";
}
@Override
public UniqueConstraint[] uniqueConstraints() {
return new UniqueConstraint[0];
}
@Override
public Index[] indexes() {
return new Index[0];
}
@Override
public Class<? extends Annotation> annotationType() {
return TableGenerator.class;
}
},
builder
);
return builder.build();
}
private static IdentifierGeneratorDefinition buildSequenceGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretSequenceGenerator(
new SequenceGenerator() {
@Override
public String name() {
return name;
}
@Override
public String sequenceName() {
return "";
}
@Override
public String catalog() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public int initialValue() {
return 1;
}
@Override
public int allocationSize() {
return 50;
}
@Override
public Class<? extends Annotation> annotationType() {
return SequenceGenerator.class;
}
},
builder
);
return builder.build();
}
@Override
public boolean equals(Object o) {
if ( this == o ) {

View File

@ -53,6 +53,7 @@ import org.hibernate.annotations.ParamDef;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Parent;
import org.hibernate.annotations.TimeZoneStorage;
import org.hibernate.annotations.ValueGenerationType;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
@ -91,6 +92,7 @@ import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl;
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.descriptor.java.BasicJavaType;
@ -152,6 +154,7 @@ import static org.hibernate.cfg.InheritanceState.getInheritanceStateOfSuperEntit
import static org.hibernate.cfg.InheritanceState.getSuperclassInheritanceState;
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
import static org.hibernate.cfg.annotations.HCANNHelper.findContainingAnnotation;
import static org.hibernate.cfg.annotations.PropertyBinder.generatorCreator;
import static org.hibernate.cfg.annotations.PropertyBinder.identifierGeneratorCreator;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.mapping.Constraint.hashedName;
@ -477,10 +480,10 @@ public final class AnnotationBinder {
else if ( generatorAnnotation instanceof GenericGenerator ) {
final GenericGenerator genericGenerator = (GenericGenerator) generatorAnnotation;
definitionBuilder.setName( genericGenerator.name() );
final String strategy = genericGenerator.type().equals(IdentifierGenerator.class)
final String strategy = genericGenerator.type().equals(InMemoryGenerator.class)
? genericGenerator.strategy()
: genericGenerator.type().getName();
definitionBuilder.setStrategy(strategy);
definitionBuilder.setStrategy( strategy );
for ( Parameter parameter : genericGenerator.parameters() ) {
definitionBuilder.addParam( parameter.name(), parameter.value() );
}
@ -1806,9 +1809,14 @@ public final class AnnotationBinder {
+ "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" );
}
final XProperty idProperty = inferredData.getProperty();
final Annotation generatorAnnotation = findContainingAnnotation( idProperty, IdGeneratorType.class );
if ( generatorAnnotation != null ) {
idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, generatorAnnotation ) );
final Annotation idGeneratorAnnotation = findContainingAnnotation( idProperty, IdGeneratorType.class );
final Annotation generatorAnnotation = findContainingAnnotation( idProperty, ValueGenerationType.class );
//TODO: validate that we don't have too many generator annotations and throw
if ( idGeneratorAnnotation != null ) {
idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, idGeneratorAnnotation ) );
}
else if ( generatorAnnotation != null ) {
idValue.setCustomGeneratorCreator( generatorCreator( idProperty, generatorAnnotation ) );
}
else {
final XClass entityClass = inferredData.getClassOrElement();

View File

@ -11,7 +11,6 @@ import java.lang.annotation.Repeatable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@ -41,8 +40,6 @@ import org.hibernate.annotations.SqlFragmentAlias;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext;
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
@ -74,10 +71,6 @@ import org.jboss.logging.Logger;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Index;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.UniqueConstraint;
import static org.hibernate.cfg.AnnotatedColumn.buildColumnOrFormulaFromAnnotation;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
@ -777,7 +770,7 @@ public class BinderHelper {
if ( !isEmptyAnnotationValue( generatorName ) ) {
//we have a named generator
final IdentifierGeneratorDefinition definition = getIdentifierGenerator(
final IdentifierGeneratorDefinition definition = makeIdentifierGeneratorDefinition(
generatorName,
property,
localGenerators,
@ -823,7 +816,7 @@ public class BinderHelper {
makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifiers );
}
private static IdentifierGeneratorDefinition getIdentifierGenerator(
private static IdentifierGeneratorDefinition makeIdentifierGeneratorDefinition(
String name,
XProperty idXProperty,
Map<String, IdentifierGeneratorDefinition> localGenerators,
@ -843,174 +836,21 @@ public class BinderHelper {
log.debugf( "Could not resolve explicit IdentifierGeneratorDefinition - using implicit interpretation (%s)", name );
// If we were unable to locate an actual matching named generator assume a sequence/table of the given name.
// this really needs access to the `jakarta.persistence.GenerationType` to work completely properly
//
// (the crux of HHH-12122)
// temporarily, in lieu of having access to GenerationType, assume the EnhancedSequenceGenerator
// for the purpose of testing the feasibility of the approach
final GeneratedValue generatedValueAnn = idXProperty.getAnnotation( GeneratedValue.class );
if ( generatedValueAnn == null ) {
final GeneratedValue generatedValue = idXProperty.getAnnotation( GeneratedValue.class );
if ( generatedValue == null ) {
// this should really never happen, but it's easy to protect against it...
return new IdentifierGeneratorDefinition( "assigned", "assigned" );
}
final IdGeneratorStrategyInterpreter generationInterpreter =
buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter();
final GenerationType generationType = interpretGenerationType( generatedValueAnn );
if ( generationType == null || generationType == GenerationType.SEQUENCE ) {
// NOTE : `null` will ultimately be interpreted as "hibernate_sequence"
log.debugf( "Building implicit sequence-based IdentifierGeneratorDefinition (%s)", name );
final IdentifierGeneratorDefinition.Builder builder = new IdentifierGeneratorDefinition.Builder();
generationInterpreter.interpretSequenceGenerator(
new SequenceGenerator() {
@Override
public String name() {
return name;
}
@Override
public String sequenceName() {
return "";
}
@Override
public String catalog() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public int initialValue() {
return 1;
}
@Override
public int allocationSize() {
return 50;
}
@Override
public Class<? extends Annotation> annotationType() {
return SequenceGenerator.class;
}
},
builder
);
return builder.build();
}
else if ( generationType == GenerationType.TABLE ) {
// NOTE : `null` will ultimately be interpreted as "hibernate_sequence"
log.debugf( "Building implicit table-based IdentifierGeneratorDefinition (%s)", name );
final IdentifierGeneratorDefinition.Builder builder = new IdentifierGeneratorDefinition.Builder();
generationInterpreter.interpretTableGenerator(
new TableGenerator() {
@Override
public String name() {
return name;
}
@Override
public String table() {
return "";
}
@Override
public int initialValue() {
return 0;
}
@Override
public int allocationSize() {
return 50;
}
@Override
public String catalog() {
return "";
}
@Override
public String schema() {
return "";
}
@Override
public String pkColumnName() {
return "";
}
@Override
public String valueColumnName() {
return "";
}
@Override
public String pkColumnValue() {
return "";
}
@Override
public UniqueConstraint[] uniqueConstraints() {
return new UniqueConstraint[0];
}
@Override
public Index[] indexes() {
return new Index[0];
}
@Override
public Class<? extends Annotation> annotationType() {
return TableGenerator.class;
}
},
builder
);
return builder.build();
}
// really AUTO and IDENTITY work the same in this respect, aside from the actual strategy name
final String strategyName;
if ( generationType == GenerationType.IDENTITY ) {
strategyName = "identity";
}
else {
strategyName = generationInterpreter.determineGeneratorName(
generationType,
new GeneratorNameDeterminationContext() {
@Override
public Class<?> getIdType() {
return buildingContext
.getBootstrapContext()
.getReflectionManager()
.toClass( idXProperty.getType() );
}
@Override
public String getGeneratedValueGeneratorName() {
return generatedValueAnn.generator();
}
}
);
}
log.debugf( "Building implicit generic IdentifierGeneratorDefinition (%s) : %s", name, strategyName );
return new IdentifierGeneratorDefinition(
return IdentifierGeneratorDefinition.createImplicit(
name,
strategyName,
Collections.singletonMap( IdentifierGenerator.GENERATOR_NAME, name )
buildingContext
.getBootstrapContext()
.getReflectionManager()
.toClass( idXProperty.getType() ),
generatedValue.generator(),
buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter(),
interpretGenerationType( generatedValue )
);
}

View File

@ -21,6 +21,7 @@ import org.hibernate.annotations.OptimisticLock;
import org.hibernate.annotations.ValueGenerationType;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumns;
@ -37,6 +38,7 @@ import org.hibernate.mapping.Component;
import org.hibernate.mapping.GeneratorCreator;
import org.hibernate.mapping.IdentifierGeneratorCreator;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;
@ -49,6 +51,7 @@ import org.hibernate.tuple.Generator;
import org.hibernate.tuple.AttributeBinder;
import org.hibernate.tuple.GeneratorCreationContext;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.InMemoryGenerator;
import org.jboss.logging.Logger;
import java.lang.annotation.Annotation;
@ -168,6 +171,38 @@ public class PropertyBinder {
this.declaringClassSet = true;
}
private boolean isToOneValue(Value value) {
return value instanceof ToOne;
}
public void setProperty(XProperty property) {
this.property = property;
}
public void setReturnedClass(XClass returnedClass) {
this.returnedClass = returnedClass;
}
public BasicValueBinder getBasicValueBinder() {
return basicValueBinder;
}
public Value getValue() {
return value;
}
public void setId(boolean id) {
this.isId = id;
}
public boolean isId() {
return isId;
}
public void setInheritanceStatePerClass(Map<XClass, InheritanceState> inheritanceStatePerClass) {
this.inheritanceStatePerClass = inheritanceStatePerClass;
}
private void validateBind() {
if ( property.isAnnotationPresent( Immutable.class ) ) {
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
@ -243,7 +278,8 @@ public class PropertyBinder {
if ( isId ) {
final RootClass rootClass = (RootClass) holder.getPersistentClass();
//if an xToMany, it has to be wrapped today.
//FIXME this poses a problem as the PK is the class instead of the associated class which is not really compliant with the spec
//FIXME this poses a problem as the PK is the class instead of the
// associated class which is not really compliant with the spec
if ( isXToMany || entityBinder.wrapIdsInEmbeddedComponents() ) {
Component identifier = (Component) rootClass.getIdentifier();
if (identifier == null) {
@ -270,7 +306,7 @@ public class PropertyBinder {
}
else {
rootClass.setIdentifierProperty( prop );
final org.hibernate.mapping.MappedSuperclass superclass = getMappedSuperclassOrNull(
final MappedSuperclass superclass = getMappedSuperclassOrNull(
declaringClass,
inheritanceStatePerClass,
buildingContext
@ -343,7 +379,7 @@ public class PropertyBinder {
}
private void handleNaturalId(Property prop) {
NaturalId naturalId = property.getAnnotation(NaturalId.class);
final NaturalId naturalId = property.getAnnotation(NaturalId.class);
if ( naturalId != null ) {
if ( !entityBinder.isRootEntity() ) {
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
@ -415,13 +451,14 @@ public class PropertyBinder {
* Instantiates the given generator annotation type, initializing it with the given instance of the corresponding
* generator annotation and the property's type.
*/
private <A extends Annotation> GeneratorCreator generatorCreator(XProperty property, A annotation) {
public static GeneratorCreator generatorCreator(XProperty property, Annotation annotation) {
final Member member = HCANNHelper.getUnderlyingMember( property );
final Class<? extends Annotation> annotationType = annotation.annotationType();
final ValueGenerationType generatorAnnotation = annotationType.getAnnotation( ValueGenerationType.class );
if ( generatorAnnotation == null ) {
return null;
}
checkGeneratorType( generatorAnnotation.generatedBy() );
return creationContext -> {
final Generator generator =
instantiateGenerator(
@ -438,13 +475,27 @@ public class PropertyBinder {
};
}
private static void checkGeneratorType(Class<? extends Generator> generatorClass) {
// we don't yet support the additional "fancy" operations of
// IdentifierGenerator with regular generators, though this
// would be extremely easy to add if anyone asks for it
if ( IdentifierGenerator.class.isAssignableFrom( generatorClass ) ) {
throw new AnnotationException("Generator class '" + generatorClass.getName()
+ "' implements 'IdentifierGenerator' and may not be used with '@ValueGenerationType'");
}
if ( ExportableProducer.class.isAssignableFrom( generatorClass ) ) {
throw new AnnotationException("Generator class '" + generatorClass.getName()
+ "' implements 'ExportableProducer' and may not be used with '@ValueGenerationType'");
}
}
public static IdentifierGeneratorCreator identifierGeneratorCreator(XProperty idProperty, Annotation annotation) {
final Member member = HCANNHelper.getUnderlyingMember( idProperty );
final Class<? extends Annotation> annotationType = annotation.annotationType();
final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class );
assert idGeneratorType != null;
return creationContext -> {
final IdentifierGenerator generator =
final InMemoryGenerator generator =
instantiateGenerator(
annotation,
member,
@ -505,11 +556,11 @@ public class PropertyBinder {
}
}
private void checkVersionGenerationAlways(XProperty property, Generator generator) {
private static void checkVersionGenerationAlways(XProperty property, Generator generator) {
if ( property.isAnnotationPresent(Version.class) ) {
final GenerationTiming timing = generator.getGenerationTiming();
if ( !timing.isAlways() ) {
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
throw new AnnotationException("Property '" + property.getName()
+ "' is annotated '@Version' but has a value generator with timing " + timing.name()
+ " (the value generation timing must be ALWAYS)"
);
@ -517,35 +568,4 @@ public class PropertyBinder {
}
}
private boolean isToOneValue(Value value) {
return value instanceof ToOne;
}
public void setProperty(XProperty property) {
this.property = property;
}
public void setReturnedClass(XClass returnedClass) {
this.returnedClass = returnedClass;
}
public BasicValueBinder getBasicValueBinder() {
return basicValueBinder;
}
public Value getValue() {
return value;
}
public void setId(boolean id) {
this.isId = id;
}
public boolean isId() {
return isId;
}
public void setInheritanceStatePerClass(Map<XClass, InheritanceState> inheritanceStatePerClass) {
this.inheritanceStatePerClass = inheritanceStatePerClass;
}
}

View File

@ -368,7 +368,7 @@ public class PersistentIdentifierBag<E> extends AbstractPersistentCollection<E>
final Integer loc = i++;
if ( !identifiers.containsKey( loc ) ) {
//TODO: native ids
final Object id = persister.getIdentifierGenerator().generate( getSession(), entry );
final Object id = persister.getGenerator().generate( getSession(), entry, null );
identifiers.put( loc, id );
}
}

View File

@ -18,7 +18,6 @@ import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
import org.hibernate.id.enhanced.Optimizer;
@ -42,6 +41,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
@ -253,8 +253,7 @@ public class TemporaryTable implements Exportable, Contributable {
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
.getEntityBinding( entityDescriptor.getEntityName() );
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister()
.getIdentifierGenerator();
final InMemoryGenerator identifierGenerator = entityDescriptor.getEntityPersister().getGenerator();
final boolean identityColumn = identifierGenerator instanceof PostInsertIdentifierGenerator;
final boolean hasOptimizer;
if ( identityColumn ) {

View File

@ -46,6 +46,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.relational.SchemaManager;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.spi.TypeConfiguration;
@ -183,6 +184,11 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor,
return delegate.getIdentifierGenerator( rootEntityName );
}
@Override
public InMemoryGenerator getGenerator(String rootEntityName) {
return delegate.getGenerator( rootEntityName );
}
@Override
public Map<String, Object> getProperties() {
return delegate.getProperties();

View File

@ -33,6 +33,7 @@ import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.spi.TypeConfiguration;
@ -120,9 +121,16 @@ public interface SessionFactoryImplementor
/**
* Get the identifier generator for the hierarchy
*
* @deprecated use {@link #getGenerator(String)}
*/
@Deprecated(since = "6.2")
IdentifierGenerator getIdentifierGenerator(String rootEntityName);
/**
* Get the identifier generator for the hierarchy
*/
InMemoryGenerator getGenerator(String rootEntityName);
EntityNotFoundDelegate getEntityNotFoundDelegate();

View File

@ -111,7 +111,7 @@ public abstract class AbstractSaveEventListener<C>
processIfSelfDirtinessTracker( entity, SelfDirtinessTracker::$$_hibernate_clearDirtyAttributes );
EntityPersister persister = source.getEntityPersister( entityName, entity );
Object generatedId = persister.getIdentifierGenerator().generate( source, entity );
Object generatedId = persister.getGenerator().generate( source, entity, null );
if ( generatedId == null ) {
throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() );
}
@ -127,7 +127,7 @@ public abstract class AbstractSaveEventListener<C>
LOG.debugf(
"Generated identifier: %s, using strategy: %s",
persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ),
persister.getIdentifierGenerator().getClass().getName()
persister.getGenerator().getClass().getName()
);
}
return performSave( entity, generatedId, persister, false, context, source, true );

View File

@ -122,7 +122,7 @@ public class DefaultPersistEventListener
// NOTE: entityEntry must be null to get here, so we cannot use any of its values
final EntityPersister persister = source.getFactory().getMappingMetamodel()
.getEntityDescriptor( entityName );
if ( persister.getIdentifierGenerator() instanceof ForeignGenerator ) {
if ( persister.getGenerator() instanceof ForeignGenerator ) {
if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) {
LOG.debug( "Resetting entity id attribute to null for foreign generator" );
}

View File

@ -22,18 +22,31 @@ import org.hibernate.type.Type;
import static org.hibernate.tuple.GenerationTiming.INSERT;
/**
* The general contract between a class that generates unique
* identifiers and the {@link org.hibernate.Session}. It is not
* intended that this interface ever be exposed to the application.
* It <em>is</em> intended that users implement this interface to
* provide custom identifier generation strategies.
* A classic extension point from the very earliest days of Hibernate,
* this interface is now no longer the only way to generate identifiers.
* Any {@link InMemoryGenerator} may now be used.
* <p>
* Implementors should provide a public default constructor.
* This interface extends {@code InMemoryGenerator} with some additional
* machinery for {@linkplain #configure configuration}, and for caching
* {@link #initialize(SqlStringGenerationContext) generated SQL}.
* <p>
* Implementations that accept configuration parameters should also
* implement {@link Configurable}.
* Any identifier generator, including a generator which directly implements
* {@code InMemoryGenerator}, may also implement {@link ExportableProducer}.
* For the sake of convenience, {@code PersistentIdentifierGenerator} extends
* {@code ExportableProducer}, in case the implementation needs to export
* objects to the database as part of the process of schema export.
* <p>
* Implementors <em>must</em> be thread-safe
* The {@link #configure(Type, Properties, ServiceRegistry)} method accepts
* a properties object containing named values. These include:
* <ul>
* <li>several "standard" parameters with keys defined as static members of
* this interface: {@value #ENTITY_NAME}, {@value #JPA_ENTITY_NAME},
* {@value #GENERATOR_NAME}, {@value #CONTRIBUTOR_NAME}, along with
* <li>additional parameters supplied by Hibernate to its built-in generators,
* depending on the generator class, and, possibly,
* <li>{@linkplain org.hibernate.annotations.Parameter parameters} specified
* using {@link org.hibernate.annotations.GenericGenerator#parameters()}.
* </ul>
*
* @author Gavin King
*

View File

@ -0,0 +1,132 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.id.factory.internal;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.enhanced.LegacyNamingStrategy;
import org.hibernate.id.enhanced.SingleNamingStrategy;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import java.util.Properties;
public class IdentifierGeneratorUtil {
public static IdentifierGenerator createLegacyIdentifierGenerator(
SimpleValue simpleValue,
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
RootClass rootClass) {
final Properties params = new Properties();
// This is for backwards compatibility only;
// when this method is called by Hibernate ORM, defaultSchema and defaultCatalog are always
// null, and defaults are handled later.
if ( defaultSchema != null ) {
params.setProperty( PersistentIdentifierGenerator.SCHEMA, defaultSchema);
}
if ( defaultCatalog != null ) {
params.setProperty( PersistentIdentifierGenerator.CATALOG, defaultCatalog);
}
// default initial value and allocation size per-JPA defaults
params.setProperty( OptimizableGenerator.INITIAL_PARAM, String.valueOf( OptimizableGenerator.DEFAULT_INITIAL_VALUE ) );
final ConfigurationService cs = simpleValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry()
.getService( ConfigurationService.class );
final String idNamingStrategy = cs.getSetting(
AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
StandardConverters.STRING,
null
);
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
params.setProperty( OptimizableGenerator.INCREMENT_PARAM, "1" );
}
else {
params.setProperty(
OptimizableGenerator.INCREMENT_PARAM,
String.valueOf( OptimizableGenerator.DEFAULT_INCREMENT_SIZE )
);
}
//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);
params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
//pass the column name (a generated id almost always has a single column)
final String columnName = ( (Column) simpleValue.getSelectables().get(0) ).getQuotedName(dialect);
params.setProperty( PersistentIdentifierGenerator.PK, columnName );
//pass the entity-name, if not a collection-id
if ( rootClass != null ) {
params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
// The table name is not really a good default for subselect entities, so use the JPA entity name which is short
if ( simpleValue.getTable().isSubselect() ) {
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, rootClass.getJpaEntityName() );
}
else {
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, simpleValue.getTable().getName() );
}
final StringBuilder tables = new StringBuilder();
for ( Table table : rootClass.getIdentityTables() ) {
tables.append( table.getQuotedName(dialect) );
if ( tables.length()>0 ) {
tables.append( ", " );
}
}
params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
}
else {
params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, tableName );
}
if ( simpleValue.getIdentifierGeneratorParameters() != null ) {
params.putAll( simpleValue.getIdentifierGeneratorParameters() );
}
// TODO : we should pass along all settings once "config lifecycle" is hashed out...
params.put(
IdentifierGenerator.CONTRIBUTOR_NAME,
simpleValue.getBuildingContext().getCurrentContributorName()
);
if ( cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) != null ) {
params.put(
AvailableSettings.PREFERRED_POOLED_OPTIMIZER,
cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER )
);
}
return identifierGeneratorFactory.createIdentifierGenerator(
simpleValue.getIdentifierGeneratorStrategy(),
simpleValue.getType(),
params
);
}
}

View File

@ -52,7 +52,7 @@ import org.hibernate.type.descriptor.java.JavaType;
import static org.hibernate.id.factory.IdGenFactoryLogging.ID_GEN_FAC_LOGGER;
/**
* Basic {@code templated} support for {@link org.hibernate.id.factory.IdentifierGeneratorFactory} implementations.
* Basic implementation of {@link org.hibernate.id.factory.IdentifierGeneratorFactory}.
*
* @author Steve Ebersole
*/

View File

@ -124,6 +124,7 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tool.schema.spi.DelayedDropAction;
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.spi.TypeConfiguration;
@ -183,7 +184,7 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
private volatile DelayedDropAction delayedDropAction;
// todo : move to MetamodelImpl
private final transient Map<String,IdentifierGenerator> identifierGenerators;
private final transient Map<String, InMemoryGenerator> identifierGenerators;
private final transient Map<String, FilterDefinition> filters;
private final transient Map<String, FetchProfile> fetchProfiles;
@ -293,12 +294,14 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
//Generators:
this.identifierGenerators = new HashMap<>();
bootMetamodel.getEntityBindings().stream().filter( model -> !model.isInherited() ).forEach( model -> {
final IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(
final InMemoryGenerator generator = model.getIdentifier().createGenerator(
bootstrapContext.getIdentifierGeneratorFactory(),
jdbcServices.getJdbcEnvironment().getDialect(),
(RootClass) model
);
generator.initialize( sqlStringGenerationContext );
if ( generator instanceof IdentifierGenerator ) {
( (IdentifierGenerator) generator ).initialize( sqlStringGenerationContext );
}
identifierGenerators.put( model.getEntityName(), generator );
} );
bootMetamodel.validate();
@ -985,8 +988,14 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
return unmodifiableSet( fetchProfiles.keySet() );
}
@Deprecated
public IdentifierGenerator getIdentifierGenerator(String rootEntityName) {
return identifierGenerators.get(rootEntityName);
return (IdentifierGenerator) getGenerator( rootEntityName );
}
@Deprecated
public InMemoryGenerator getGenerator(String rootEntityName) {
return identifierGenerators.get( rootEntityName );
}
private boolean canAccessTransactionManager() {

View File

@ -93,7 +93,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public Object insert(String entityName, Object entity) {
checkOpen();
EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifierGenerator().generate( this, entity );
Object id = persister.getGenerator().generate( this, entity, null );
Object[] state = persister.getValues( entity );
if ( persister.isVersioned() ) {
boolean substitute = Versioning.seedVersion(

View File

@ -18,6 +18,7 @@ import java.util.stream.Collectors;
import org.hibernate.MappingException;
import org.hibernate.Remove;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
@ -33,6 +34,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.ComponentType;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.Type;
@ -70,7 +72,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
private transient List<Column> cachedColumns;
private transient IdentifierGenerator builtIdentifierGenerator;
private transient InMemoryGenerator builtIdentifierGenerator;
public Component(MetadataBuildingContext metadata, PersistentClass owner) throws MappingException {
this( metadata, owner.getTable(), owner );
@ -412,34 +414,30 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
}
@Override
public IdentifierGenerator createIdentifierGenerator(
public InMemoryGenerator createGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
RootClass rootClass) throws MappingException {
if ( builtIdentifierGenerator == null ) {
builtIdentifierGenerator = buildIdentifierGenerator(
identifierGeneratorFactory,
dialect,
defaultCatalog,
defaultSchema,
rootClass
);
}
return builtIdentifierGenerator;
}
private IdentifierGenerator buildIdentifierGenerator(
private InMemoryGenerator buildIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
RootClass rootClass) throws MappingException {
final boolean hasCustomGenerator = ! DEFAULT_ID_GEN_STRATEGY.equals( getIdentifierGeneratorStrategy() );
if ( hasCustomGenerator ) {
return super.createIdentifierGenerator(
identifierGeneratorFactory, dialect, defaultCatalog, defaultSchema, rootClass
return super.createGenerator(
identifierGeneratorFactory,
dialect,
rootClass
);
}
@ -469,25 +467,16 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
if ( property.getValue().isSimpleValue() ) {
final SimpleValue value = (SimpleValue) property.getValue();
if ( DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) {
if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) {
// skip any 'assigned' generators, they would have been handled by
// the StandardGenerationContextLocator
continue;
generator.addGeneratedValuePlan(
new ValueGenerationPlan(
value.createGenerator( identifierGeneratorFactory, dialect, rootClass ),
injector( property, attributeDeclarer )
)
);
}
final IdentifierGenerator valueGenerator = value.createIdentifierGenerator(
identifierGeneratorFactory,
dialect,
defaultCatalog,
defaultSchema,
rootClass
);
generator.addGeneratedValuePlan(
new ValueGenerationPlan(
valueGenerator,
injector( property, attributeDeclarer )
)
);
}
}
return generator;
@ -523,11 +512,11 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
}
public static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan {
private final IdentifierGenerator subGenerator;
private final InMemoryGenerator subGenerator;
private final Setter injector;
public ValueGenerationPlan(
IdentifierGenerator subGenerator,
InMemoryGenerator subGenerator,
Setter injector) {
this.subGenerator = subGenerator;
this.injector = injector;
@ -535,18 +524,21 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
@Override
public void execute(SharedSessionContractImplementor session, Object incomingObject, Object injectionContext) {
final Object generatedValue = subGenerator.generate( session, incomingObject );
injector.set( injectionContext, generatedValue );
injector.set( injectionContext, subGenerator.generate( session, incomingObject, null ) );
}
@Override
public void registerExportables(Database database) {
subGenerator.registerExportables( database );
if ( subGenerator instanceof ExportableProducer ) {
( (ExportableProducer) subGenerator ).registerExportables( database );
}
}
@Override
public void initialize(SqlStringGenerationContext context) {
subGenerator.initialize( context );
if ( subGenerator instanceof IdentifierGenerator ) {
( (IdentifierGenerator) subGenerator ).initialize( context );
}
}
}

View File

@ -6,10 +6,10 @@
*/
package org.hibernate.mapping;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
import org.hibernate.tuple.InMemoryGenerator;
@FunctionalInterface
public interface IdentifierGeneratorCreator {
IdentifierGenerator createGenerator(CustomIdGeneratorCreationContext context);
InMemoryGenerator createGenerator(CustomIdGeneratorCreationContext context);
}

View File

@ -6,10 +6,10 @@
*/
package org.hibernate.mapping;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.tuple.InMemoryGenerator;
/**
* A mapping model {@link Value} which may be treated as an identifying key of a
@ -21,23 +21,6 @@ import org.hibernate.id.factory.IdentifierGeneratorFactory;
*/
public interface KeyValue extends Value {
/**
* @deprecated Use {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, RootClass)}
* instead.
*/
@Deprecated
IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
RootClass rootClass) throws MappingException;
IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
RootClass rootClass) throws MappingException;
boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect);
ForeignKey createForeignKeyOfEntity(String entityName);
@ -47,4 +30,34 @@ public interface KeyValue extends Value {
String getNullValue();
boolean isUpdateable();
InMemoryGenerator createGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
RootClass rootClass);
/**
* @deprecated Use {@link #createGenerator(IdentifierGeneratorFactory, Dialect, RootClass)} instead.
*/
@Deprecated
default IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
RootClass rootClass) {
return (IdentifierGenerator) createGenerator( identifierGeneratorFactory, dialect, rootClass );
}
/**
* @deprecated Use {@link #createGenerator(IdentifierGeneratorFactory, Dialect, RootClass)} instead.
*/
@Deprecated
default IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
RootClass rootClass) {
return (IdentifierGenerator) createGenerator( identifierGeneratorFactory, dialect, rootClass );
}
}

View File

@ -34,17 +34,10 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.enhanced.LegacyNamingStrategy;
import org.hibernate.id.enhanced.SingleNamingStrategy;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
import org.hibernate.internal.CoreLogging;
@ -54,6 +47,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.java.JavaType;
@ -67,6 +61,8 @@ import org.hibernate.usertype.DynamicParameterizedType;
import jakarta.persistence.AttributeConverter;
import static org.hibernate.id.factory.internal.IdentifierGeneratorUtil.createLegacyIdentifierGenerator;
/**
* A mapping model object that represents any value that maps to columns.
*
@ -104,6 +100,10 @@ public abstract class SimpleValue implements KeyValue {
private ConverterDescriptor attributeConverterDescriptor;
private Type type;
private IdentifierGeneratorCreator customIdGeneratorCreator;
private GeneratorCreator customGeneratorCreator;
private InMemoryGenerator generator;
public SimpleValue(MetadataBuildingContext buildingContext) {
this.buildingContext = buildingContext;
this.metadata = buildingContext.getMetadataCollector();
@ -136,7 +136,7 @@ public abstract class SimpleValue implements KeyValue {
this.attributeConverterDescriptor = original.attributeConverterDescriptor;
this.type = original.type;
this.customIdGeneratorCreator = original.customIdGeneratorCreator;
this.identifierGenerator = original.identifierGenerator;
this.generator = original.generator;
}
public MetadataBuildingContext getBuildingContext() {
@ -359,9 +359,6 @@ public abstract class SimpleValue implements KeyValue {
getTable().createUniqueKey( getConstraintColumns() );
}
private IdentifierGeneratorCreator customIdGeneratorCreator;
private IdentifierGenerator identifierGenerator;
/**
* Returns the cached {@link IdentifierGenerator}, or null if
* {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, String, String, RootClass)}
@ -371,7 +368,7 @@ public abstract class SimpleValue implements KeyValue {
*/
@Deprecated(since = "6.0")
public IdentifierGenerator getIdentifierGenerator() {
return identifierGenerator;
return (IdentifierGenerator) generator;
}
public void setCustomIdGeneratorCreator(IdentifierGeneratorCreator customIdGeneratorCreator) {
@ -382,171 +379,41 @@ public abstract class SimpleValue implements KeyValue {
return customIdGeneratorCreator;
}
@Override
public IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
RootClass rootClass) throws MappingException {
return createIdentifierGenerator( identifierGeneratorFactory, dialect, null, null, rootClass );
public GeneratorCreator getCustomGeneratorCreator() {
return customGeneratorCreator;
}
public void setCustomGeneratorCreator(GeneratorCreator customGeneratorCreator) {
this.customGeneratorCreator = customGeneratorCreator;
}
@Override
public IdentifierGenerator createIdentifierGenerator(
public InMemoryGenerator createGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
String defaultCatalog,
String defaultSchema,
Dialect dialect,
RootClass rootClass) throws MappingException {
if ( identifierGenerator != null ) {
return identifierGenerator;
if ( generator != null ) {
return generator;
}
if ( customIdGeneratorCreator != null ) {
final CustomIdGeneratorCreationContext creationContext = new CustomIdGeneratorCreationContext() {
@Override
public IdentifierGeneratorFactory getIdentifierGeneratorFactory() {
return identifierGeneratorFactory;
}
@Override
public Database getDatabase() {
return buildingContext.getMetadataCollector().getDatabase();
}
@Override
public ServiceRegistry getServiceRegistry() {
return buildingContext.getBootstrapContext().getServiceRegistry();
}
@Override
public String getDefaultCatalog() {
return defaultCatalog;
}
@Override
public String getDefaultSchema() {
return defaultSchema;
}
@Override
public RootClass getRootClass() {
return rootClass;
}
@Override
public PersistentClass getPersistentClass() {
return rootClass;
}
@Override
public Property getProperty() {
return rootClass.getIdentifierProperty();
}
};
identifierGenerator = customIdGeneratorCreator.createGenerator( creationContext );
return identifierGenerator;
}
final Properties params = new Properties();
// This is for backwards compatibility only;
// when this method is called by Hibernate ORM, defaultSchema and defaultCatalog are always
// null, and defaults are handled later.
if ( defaultSchema != null ) {
params.setProperty( PersistentIdentifierGenerator.SCHEMA, defaultSchema);
}
if ( defaultCatalog != null ) {
params.setProperty( PersistentIdentifierGenerator.CATALOG, defaultCatalog );
}
// default initial value and allocation size per-JPA defaults
params.setProperty( OptimizableGenerator.INITIAL_PARAM, String.valueOf( OptimizableGenerator.DEFAULT_INITIAL_VALUE ) );
final ConfigurationService cs = metadata.getMetadataBuildingOptions().getServiceRegistry()
.getService( ConfigurationService.class );
final String idNamingStrategy = cs.getSetting(
AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
StandardConverters.STRING,
null
);
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
params.setProperty( OptimizableGenerator.INCREMENT_PARAM, "1" );
}
else {
params.setProperty(
OptimizableGenerator.INCREMENT_PARAM,
String.valueOf( OptimizableGenerator.DEFAULT_INCREMENT_SIZE )
generator = customIdGeneratorCreator.createGenerator(
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
);
return generator;
}
//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 = getTable().getQuotedName( dialect );
params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
//pass the column name (a generated id almost always has a single column)
final String columnName = ( (Column) getSelectables().get(0) ).getQuotedName( dialect );
params.setProperty( PersistentIdentifierGenerator.PK, columnName );
//pass the entity-name, if not a collection-id
if ( rootClass != null ) {
params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
// The table name is not really a good default for subselect entities, so use the JPA entity name which is short
if ( getTable().isSubselect() ) {
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, rootClass.getJpaEntityName() );
}
else {
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, getTable().getName() );
}
final StringBuilder tables = new StringBuilder();
final Iterator<Table> itr = rootClass.getIdentityTables().iterator();
while ( itr.hasNext() ) {
final Table table = itr.next();
tables.append( table.getQuotedName( dialect ) );
if ( itr.hasNext() ) {
tables.append( ", " );
}
}
params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
}
else {
params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, tableName );
}
if ( identifierGeneratorParameters != null ) {
params.putAll(identifierGeneratorParameters);
}
// TODO : we should pass along all settings once "config lifecycle" is hashed out...
params.put(
IdentifierGenerator.CONTRIBUTOR_NAME,
buildingContext.getCurrentContributorName()
);
if ( cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) != null ) {
params.put(
AvailableSettings.PREFERRED_POOLED_OPTIMIZER,
cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER )
else if ( customGeneratorCreator != null ) {
// we may as well allow this, so you don't have to annotate generator
// annotations twice, with @IdGeneratorType and @ValueGenerationType
//TODO: this typecast is ugly ... throw a better exception at least
generator = (InMemoryGenerator) customGeneratorCreator.createGenerator(
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
);
return generator;
}
identifierGenerator = identifierGeneratorFactory.createIdentifierGenerator(
identifierGeneratorStrategy,
getType(),
params
);
return identifierGenerator;
generator = createLegacyIdentifierGenerator(this, identifierGeneratorFactory, dialect, null, null, rootClass );
return generator;
}
public boolean isUpdateable() {
@ -1185,4 +1052,58 @@ public abstract class SimpleValue implements KeyValue {
return columnLengths;
}
}
private class IdGeneratorCreationContext implements CustomIdGeneratorCreationContext {
private final IdentifierGeneratorFactory identifierGeneratorFactory;
private final String defaultCatalog;
private final String defaultSchema;
private final RootClass rootClass;
public IdGeneratorCreationContext(IdentifierGeneratorFactory identifierGeneratorFactory, String defaultCatalog, String defaultSchema, RootClass rootClass) {
this.identifierGeneratorFactory = identifierGeneratorFactory;
this.defaultCatalog = defaultCatalog;
this.defaultSchema = defaultSchema;
this.rootClass = rootClass;
}
@Override
public IdentifierGeneratorFactory getIdentifierGeneratorFactory() {
return identifierGeneratorFactory;
}
@Override
public Database getDatabase() {
return buildingContext.getMetadataCollector().getDatabase();
}
@Override
public ServiceRegistry getServiceRegistry() {
return buildingContext.getBootstrapContext().getServiceRegistry();
}
@Override
public String getDefaultCatalog() {
return defaultCatalog;
}
@Override
public String getDefaultSchema() {
return defaultSchema;
}
@Override
public RootClass getRootClass() {
return rootClass;
}
@Override
public PersistentClass getPersistentClass() {
return rootClass;
}
@Override
public Property getProperty() {
return rootClass.getIdentifierProperty();
}
}
}

View File

@ -128,6 +128,7 @@ import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
@ -225,7 +226,7 @@ public abstract class AbstractCollectionPersister
protected final SqlExceptionHelper sqlExceptionHelper;
private final SessionFactoryImplementor factory;
private final EntityPersister ownerPersister;
private final IdentifierGenerator identifierGenerator;
private final InMemoryGenerator identifierGenerator;
private final PropertyMapping elementPropertyMapping;
private final EntityPersister elementPersister;
private final CollectionDataAccess cacheAccessStrategy;
@ -509,12 +510,14 @@ public abstract class AbstractCollectionPersister
Column col = idColl.getIdentifier().getColumns().get(0);
identifierColumnName = col.getQuotedName( dialect );
identifierColumnAlias = col.getAlias( dialect );
identifierGenerator = idColl.getIdentifier().createIdentifierGenerator(
identifierGenerator = idColl.getIdentifier().createGenerator(
creationContext.getBootstrapContext().getIdentifierGeneratorFactory(),
factory.getJdbcServices().getDialect(),
null
);
identifierGenerator.initialize( creationContext.getSessionFactory().getSqlStringGenerationContext() );
if ( identifierGenerator instanceof IdentifierGenerator ) {
( (IdentifierGenerator) identifierGenerator ).initialize( creationContext.getSessionFactory().getSqlStringGenerationContext() );
}
}
else {
identifierType = null;
@ -1139,8 +1142,13 @@ public abstract class AbstractCollectionPersister
return ownerPersister;
}
@Override
@Override @Deprecated
public IdentifierGenerator getIdentifierGenerator() {
return (IdentifierGenerator) identifierGenerator;
}
@Override
public InMemoryGenerator getGenerator() {
return identifierGenerator;
}

View File

@ -33,6 +33,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
@ -231,9 +232,19 @@ public interface CollectionPersister extends Restrictable {
/**
* Get the surrogate key generation strategy (optional operation)
*
* @deprecated use {@link #getGenerator()}
*/
@Deprecated
IdentifierGenerator getIdentifierGenerator();
/**
* Get the surrogate key generation strategy (optional operation)
*/
default InMemoryGenerator getGenerator() {
return getIdentifierGenerator();
}
/**
* Get the type of the surrogate key
*/

View File

@ -259,6 +259,7 @@ import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.Generator;
import org.hibernate.tuple.InDatabaseGenerator;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
import org.hibernate.tuple.entity.EntityMetamodel;
@ -3936,11 +3937,16 @@ public abstract class AbstractEntityPersister
return entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
}
@Override
@Override @Deprecated
public IdentifierGenerator getIdentifierGenerator() throws HibernateException {
return entityMetamodel.getIdentifierProperty().getIdentifierGenerator();
}
@Override
public InMemoryGenerator getGenerator() {
return entityMetamodel.getIdentifierProperty().getGenerator();
}
@Override
public String getRootEntityName() {
return entityMetamodel.getRootName();
@ -4821,9 +4827,9 @@ public abstract class AbstractEntityPersister
sqmMultiTableMutationStrategy = null;
}
if ( !needsMultiTableInsert && getIdentifierGenerator() instanceof BulkInsertionCapableIdentifierGenerator ) {
if ( getIdentifierGenerator() instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) getIdentifierGenerator() ).getOptimizer();
if ( !needsMultiTableInsert && getGenerator() instanceof BulkInsertionCapableIdentifierGenerator ) {
if ( getGenerator() instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) getGenerator() ).getOptimizer();
needsMultiTableInsert = optimizer != null && optimizer.getIncrementSize() > 1;
}
}

View File

@ -44,6 +44,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
@ -451,9 +452,16 @@ public interface EntityPersister
* Determine which identifier generation strategy is used for this entity.
*
* @return The identifier generation strategy.
*
* @deprecated use {@link #getGenerator()}
*/
@Deprecated
IdentifierGenerator getIdentifierGenerator();
default InMemoryGenerator getGenerator() {
return getIdentifierGenerator();
}
@Override
default AttributeMapping getAttributeMapping(int position) {
return getAttributeMappings().get( position );

View File

@ -112,7 +112,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, creationContext );
if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
if ( getGenerator() instanceof IdentityGenerator ) {
throw new MappingException(
"Cannot use identity column key generation with <union-subclass> mapping for: " +
getEntityName()

View File

@ -44,7 +44,6 @@ import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.CoreLogging;
@ -108,6 +107,7 @@ import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.tuple.InMemoryGenerator;
import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE;
import static org.hibernate.jpa.HibernateHints.HINT_CACHE_MODE;
@ -838,8 +838,9 @@ public class QuerySqmImpl<R>
boolean useMultiTableInsert = entityDescriptor.isMultiTable();
if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, entityDescriptor ) ) {
final IdentifierGenerator identifierGenerator = entityDescriptor.getIdentifierGenerator();
if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator && identifierGenerator instanceof OptimizableGenerator ) {
final InMemoryGenerator identifierGenerator = entityDescriptor.getGenerator();
if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
&& identifierGenerator instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, entityDescriptor );

View File

@ -21,7 +21,6 @@ import org.hibernate.dialect.temptable.TemporaryTable;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
import org.hibernate.id.enhanced.Optimizer;
@ -95,6 +94,7 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -273,7 +273,7 @@ public class CteInsertHandler implements InsertHandler {
rowNumberColumn
);
}
if ( !assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator ) {
if ( !assignsId && entityDescriptor.getGenerator() instanceof PostInsertIdentifierGenerator ) {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
1,
@ -337,7 +337,7 @@ public class CteInsertHandler implements InsertHandler {
processingStateStack.push( oldState );
sqmConverter.pruneTableGroupJoins();
if ( !assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator ) {
if ( !assignsId && entityDescriptor.getGenerator() instanceof PostInsertIdentifierGenerator ) {
// Add the row number to the assignments
final CteColumn rowNumberColumn = cteTable.getCteColumns()
.get( cteTable.getCteColumns().size() - 1 );
@ -389,7 +389,7 @@ public class CteInsertHandler implements InsertHandler {
);
final CteColumn idColumn = fullEntityCteTable.getCteColumns().get( 0 );
final BasicValuedMapping idType = (BasicValuedMapping) idColumn.getJdbcMapping();
final Optimizer optimizer = ( (OptimizableGenerator) entityDescriptor.getIdentifierGenerator() ).getOptimizer();
final Optimizer optimizer = ( (OptimizableGenerator) entityDescriptor.getGenerator() ).getOptimizer();
final BasicValuedMapping integerType = (BasicValuedMapping) rowNumberColumn.getJdbcMapping();
final Expression rowNumberMinusOneModuloIncrement = new BinaryArithmeticExpression(
new BinaryArithmeticExpression(
@ -428,7 +428,7 @@ public class CteInsertHandler implements InsertHandler {
rowNumberColumnReference
)
);
final String fragment = ( (BulkInsertionCapableIdentifierGenerator) entityDescriptor.getIdentifierGenerator() )
final String fragment = ( (BulkInsertionCapableIdentifierGenerator) entityDescriptor.getGenerator() )
.determineBulkInsertionIdentifierGenerationSelectFragment(
sessionFactory.getSqlStringGenerationContext()
);
@ -581,7 +581,7 @@ public class CteInsertHandler implements InsertHandler {
statement.addCteStatement( entityCte );
}
}
else if ( !assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator ) {
else if ( !assignsId && entityDescriptor.getGenerator() instanceof PostInsertIdentifierGenerator ) {
final String baseTableName = "base_" + entityCteTable.getTableExpression();
final CteStatement baseEntityCte = new CteStatement(
entityCteTable.withName( baseTableName ),
@ -775,7 +775,7 @@ public class CteInsertHandler implements InsertHandler {
true
);
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
final InMemoryGenerator identifierGenerator = entityDescriptor.getEntityPersister().getGenerator();
final List<Map.Entry<List<CteColumn>, Assignment>> tableAssignments = assignmentsByTable.get( rootTableReference );
if ( ( tableAssignments == null || tableAssignments.isEmpty() ) && !( identifierGenerator instanceof PostInsertIdentifierGenerator ) ) {
throw new IllegalStateException( "There must be at least a single root table assignment" );

View File

@ -23,7 +23,6 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
import org.hibernate.id.PostInsertIdentityPersister;
@ -74,6 +73,7 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.descriptor.ValueBinder;
/**
@ -301,7 +301,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
true
);
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
final InMemoryGenerator identifierGenerator = entityDescriptor.getEntityPersister().getGenerator();
final List<Assignment> assignments = assignmentsByTable.get( updatingTableReference );
if ( ( assignments == null || assignments.isEmpty() )
&& !( identifierGenerator instanceof PostInsertIdentifierGenerator )
@ -507,10 +507,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
rootIdentity,
new JdbcParameterBindingImpl(
identifierMapping.getJdbcMapping(),
identifierGenerator.generate(
executionContext.getSession(),
null
)
identifierGenerator.generate( executionContext.getSession(), null, null )
)
);
jdbcServices.getJdbcMutationExecutor().execute(
@ -654,7 +651,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
}
}
private boolean needsIdentifierGeneration(IdentifierGenerator identifierGenerator) {
private boolean needsIdentifierGeneration(InMemoryGenerator identifierGenerator) {
if ( !( identifierGenerator instanceof OptimizableGenerator ) ) {
return false;
}
@ -721,7 +718,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
}
final String targetKeyColumnName = keyColumns[0];
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityDescriptor.getEntityPersister();
final IdentifierGenerator identifierGenerator = entityPersister.getIdentifierGenerator();
final InMemoryGenerator identifierGenerator = entityPersister.getGenerator();
final boolean needsKeyInsert;
if ( identifierGenerator instanceof PostInsertIdentifierGenerator ) {
needsKeyInsert = true;

View File

@ -20,7 +20,6 @@ import org.hibernate.dialect.temptable.TemporaryTableColumn;
import org.hibernate.dialect.temptable.TemporaryTableSessionUidColumn;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.util.collections.CollectionHelper;
@ -53,6 +52,7 @@ import org.hibernate.sql.ast.tree.update.Assignment;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.BasicType;
import org.jboss.logging.Logger;
@ -201,8 +201,8 @@ public class TableBasedInsertHandler implements InsertHandler {
new Assignment( columnReference, columnReference )
);
}
else if ( entityDescriptor.getIdentifierGenerator() instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) entityDescriptor.getIdentifierGenerator() ).getOptimizer();
else if ( entityDescriptor.getGenerator() instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) entityDescriptor.getGenerator() ).getOptimizer();
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
if ( !sessionFactory.getJdbcServices().getDialect().supportsWindowFunctions() ) {
return;
@ -254,7 +254,7 @@ public class TableBasedInsertHandler implements InsertHandler {
}
else {
// Add the row number column if there is one
final IdentifierGenerator generator = entityDescriptor.getIdentifierGenerator();
final InMemoryGenerator generator = entityDescriptor.getGenerator();
final BasicType<?> rowNumberType;
if ( generator instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) generator ).getOptimizer();

View File

@ -44,7 +44,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
import org.hibernate.id.enhanced.Optimizer;
@ -384,6 +383,7 @@ import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiation;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
@ -1225,18 +1225,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
EntityPersister entityDescriptor, TableGroup rootTableGroup) {
final List<SqmPath<?>> targetPaths = sqmStatement.getInsertionTargetPaths();
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
IdentifierGenerator identifierGenerator = entityDescriptor.getIdentifierGenerator();
Expression versionExpression = null;
Expression discriminatorExpression = null;
BasicEntityIdentifierMapping identifierMapping = null;
// We use the id property name to null the identifier generator variable if the target paths contain the id
final String identifierPropertyName;
if ( identifierGenerator != null ) {
identifierPropertyName = entityDescriptor.getIdentifierPropertyName();
}
else {
identifierPropertyName = null;
}
InMemoryGenerator identifierGenerator = entityDescriptor.getGenerator();
identifierPropertyName = identifierGenerator != null ? entityDescriptor.getIdentifierPropertyName() : null;
final String versionAttributeName;
boolean needsVersionInsert;
if ( entityDescriptor.isVersioned() ) {
@ -1351,7 +1346,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
public static class AdditionalInsertValues {
private final Expression versionExpression;
private final Expression discriminatorExpression;
private final IdentifierGenerator identifierGenerator;
private final InMemoryGenerator identifierGenerator;
private final BasicEntityIdentifierMapping identifierMapping;
private Expression identifierGeneratorParameter;
private SqlSelection versionSelection;
@ -1361,7 +1356,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
public AdditionalInsertValues(
Expression versionExpression,
Expression discriminatorExpression,
IdentifierGenerator identifierGenerator,
InMemoryGenerator identifierGenerator,
BasicEntityIdentifierMapping identifierMapping) {
this.versionExpression = versionExpression;
this.discriminatorExpression = discriminatorExpression;
@ -1453,9 +1448,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private static class IdGeneratorParameter extends AbstractJdbcParameter {
private final IdentifierGenerator generator;
private final InMemoryGenerator generator;
public IdGeneratorParameter(BasicEntityIdentifierMapping identifierMapping, IdentifierGenerator generator) {
public IdGeneratorParameter(BasicEntityIdentifierMapping identifierMapping, InMemoryGenerator generator) {
super( identifierMapping.getJdbcMapping() );
this.generator = generator;
}
@ -1468,7 +1463,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
ExecutionContext executionContext) throws SQLException {
getJdbcMapping().getJdbcValueBinder().bind(
statement,
generator.generate( executionContext.getSession(), null ),
generator.generate( executionContext.getSession(), null, null ),
startPosition,
executionContext.getSession()
);

View File

@ -11,18 +11,22 @@ import java.lang.reflect.Member;
/**
* A {@link Generator} based on a custom Java generator annotation type.
* Every instance must implement either {@link InMemoryGenerator} or
* {@link InDatabaseGenerator}. Implementing this interface is just a
* slightly more typesafe alternative to providing a constructor with
* the same signature as the method
* {@link #initialize(Annotation, Member, GeneratorCreationContext)}.
* A {@link Generator} which receives parameters from a custom
* {@linkplain org.hibernate.annotations.ValueGenerationType generator annotation} or
* {@linkplain org.hibernate.annotations.IdGeneratorType id generator annotation}.
* <p>
* Implementing this interface is the same as providing a constructor with the same
* signature as the {@link #initialize} method. But implementing this interface is
* slightly more typesafe.
* <p>
* Every instance of this class must implement either {@link InMemoryGenerator} or
* {@link InDatabaseGenerator}.
*
* @param <A> The generator annotation type supported by an implementation
*
* @see org.hibernate.annotations.ValueGenerationType
* @see org.hibernate.annotations.IdGeneratorType
*
* @author Gunnar Morling
* @author Gavin King
*
* @since 6.2
@ -31,8 +35,9 @@ public interface AnnotationBasedGenerator<A extends Annotation> extends Generato
/**
* Initializes this generation strategy for the given annotation instance.
*
* @param annotation an instance of the strategy's annotation type. Typically, implementations will retrieve the
* annotation's attribute values and store them in fields.
* @param annotation an instance of the strategy's annotation type. Typically,
* implementations will retrieve the annotation's attribute
* values and store them in fields.
* @param member the Java member annotated with the generator annotation.
* @param context a {@link GeneratorCreationContext}
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if

View File

@ -15,23 +15,29 @@ import java.lang.reflect.Method;
/**
* A {@link ValueGeneration} based on a custom Java generator annotation type.
* An implementation of {@link ValueGeneration} which receives parameters from a custom
* {@linkplain org.hibernate.annotations.ValueGenerationType generator annotation}.
* <p>
* This is an older API that predates {@link Generator} and {@link AnnotationBasedGenerator}.
* It's often cleaner to implement {@code AnnotationBasedGenerator} directly.
*
* @param <A> The generator annotation type supported by an implementation
*
* @see org.hibernate.annotations.ValueGenerationType
*
* @author Gunnar Morling
*
* @see ValueGeneration
*/
public interface AnnotationValueGeneration<A extends Annotation>
extends ValueGeneration, AnnotationBasedGenerator<A> {
/**
* Initializes this generation strategy for the given annotation instance.
*
* @param annotation an instance of the strategy's annotation type. Typically, implementations will retrieve the
* annotation's attribute values and store them in fields.
* @param propertyType the type of the property annotated with the generator annotation. Implementations may use
* the type to determine the right {@link ValueGenerator} to be applied.
* @param annotation an instance of the strategy's annotation type. Typically,
* implementations will retrieve the annotation's attribute
* values and store them in fields.
* @param propertyType the type of the property annotated with the generator annotation.
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if
* an implementation can't create a value for the given property type.
*/

View File

@ -6,15 +6,18 @@
*/
package org.hibernate.tuple;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import java.io.Serializable;
/**
* Describes the generation of values of a certain field or property of an entity. A generated
* value might be generated in Java, or by the database. Every instance must implement either
* {@link InMemoryGenerator} or {@link InDatabaseGenerator}
* depending on whether values are generated in Java code, or by the database.
* {@link InMemoryGenerator} or {@link InDatabaseGenerator} depending on whether values are
* generated in Java code, or by the database.
* <ul>
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
* <li>Value generation via arbitrary code written in Java is the responsibility of the method
* {@link InMemoryGenerator#generate(SharedSessionContractImplementor, Object, Object)}.
* In this case, the generated value is written to the database just like any other field
* or property value.
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
@ -23,11 +26,21 @@ import java.io.Serializable;
* statement. In this case, the generated value is retrieved from the database using a SQL
* {@code select}.
* </ul>
* If an implementation of {@code ValueGenerationStrategy} may be associated with an entity
* via a {@linkplain org.hibernate.annotations.ValueGenerationType custom annotation}, it
* should implement {@link AnnotationBasedGenerator}.
* A generator may receive parameters from {@linkplain org.hibernate.annotations.ValueGenerationType
* an annotation}. The generator may either:
* <ul>
* <li>implement {@link AnnotationBasedGenerator}, and receive the annotation as an argument to
* {@link AnnotationBasedGenerator#initialize},
* <li>declare a constructor with the same signature as {@link AnnotationBasedGenerator#initialize},
* <li>declare a constructor which accepts just the annotation instance, or
* <li>declare a only default constructor, in which case it will not receive parameters.
* </ul>
* On the other hand, there is some special machinery for configuring the much older interface
* {@link org.hibernate.id.IdentifierGenerator}. But this machinery is only available for
* identifier generation.
*
* @see org.hibernate.annotations.ValueGenerationType
* @see org.hibernate.annotations.IdGeneratorType
* @see org.hibernate.annotations.Generated
* @see org.hibernate.annotations.GeneratorType
*

View File

@ -16,8 +16,11 @@ public interface IdentifierAttribute extends Attribute {
boolean isEmbedded();
@Deprecated
IdentifierGenerator getIdentifierGenerator();
InMemoryGenerator getGenerator();
boolean isIdentifierAssignedByInsert();
boolean hasIdentifierMapper();

View File

@ -20,7 +20,7 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
private final boolean virtual;
private final boolean embedded;
private final IdentifierGenerator identifierGenerator;
private final InMemoryGenerator identifierGenerator;
private final boolean identifierAssignedByInsert;
private final boolean hasIdentifierMapper;
@ -38,7 +38,7 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
String name,
Type type,
boolean embedded,
IdentifierGenerator identifierGenerator) {
InMemoryGenerator identifierGenerator) {
super( name, type );
this.virtual = false;
this.embedded = embedded;
@ -59,7 +59,7 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
Type type,
boolean embedded,
boolean hasIdentifierMapper,
IdentifierGenerator identifierGenerator) {
InMemoryGenerator identifierGenerator) {
super( null, type );
this.virtual = true;
this.embedded = embedded;
@ -80,6 +80,11 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
@Override
public IdentifierGenerator getIdentifierGenerator() {
return (IdentifierGenerator) identifierGenerator;
}
@Override
public InMemoryGenerator getGenerator() {
return identifierGenerator;
}

View File

@ -14,6 +14,10 @@ import org.hibernate.dialect.Dialect;
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
* statement. In this case, the generated value is retrieved from the database using a SQL
* {@code select}.
* <p>
* Implementations should override {@link #referenceColumnsInSql()},
* {@link #writePropertyValue()}, and {@link #getReferencedColumnValues(Dialect)} as needed
* in order to achieve the desired behavior.
*
* @author Steve Ebersole
*
@ -22,9 +26,9 @@ import org.hibernate.dialect.Dialect;
public interface InDatabaseGenerator extends Generator {
/**
* Determines if the columns whose values are generated are included in the column list of
* the SQL {@code insert} or {@code update} statement, in the case where the value is
* generated by the database. For example, this method should return:
* Determines if the columns whose values are generated are included in the column list
* of the SQL {@code insert} or {@code update} statement. For example, this method should
* return:
* <ul>
* <li>{@code true} if the value is generated by calling a SQL function like
* {@code current_timestamp}, or
@ -32,10 +36,6 @@ public interface InDatabaseGenerator extends Generator {
* by {@link org.hibernate.annotations.GeneratedColumn generated always as}, or
* using a {@linkplain org.hibernate.annotations.ColumnDefault column default value}.
* </ul>
* If the value is generated in Java, this method is not called, and so for backward
* compatibility with Hibernate 5 it is permitted to return any value. On the other hand,
* when a property value is generated in Java, the column certainly must be included in
* the column list, and so it's most correct for this method to return {@code true}!
*
* @return {@code true} if the column is included in the column list of the SQL statement.
*/
@ -48,18 +48,16 @@ public interface InDatabaseGenerator extends Generator {
boolean writePropertyValue();
/**
* A SQL expression indicating how to calculate the generated values when the property values
* are {@linkplain #generatedByDatabase() generated in the database} and the mapped columns
* A SQL expression indicating how to calculate the generated values when the mapped columns
* are {@linkplain #referenceColumnsInSql() included in the SQL statement}. The SQL expressions
* might be:
* <ul>
* <li>function calls like {@code current_timestamp} or {@code nextval('mysequence')}, or
* <li>syntactic markers like {@code default}.
* </ul>
* When the property values are generated in Java, this method is not called.
*
* @param dialect The {@linkplain Dialect SQL dialect}, allowing generation of an expression
* in dialect-specific SQL.
* in dialect-specific SQL.
* @return The column value to be used in the generated SQL statement.
*/
String[] getReferencedColumnValues(Dialect dialect);

View File

@ -9,9 +9,16 @@ package org.hibernate.tuple;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Java value generation is the responsibility of an associated {@link ValueGenerator}.
* In this case, the generated value is written to the database just like any other field
* or property value.
* A generator that is called to produce a value just before a row is written to the database.
* The {@link #generate} method may execute arbitrary Java code, it may even, in principle,
* access the database via JDBC. But however it is produced, the generated value is sent to the
* database via a parameter of a JDBC prepared statement, just like any other field or property
* value.
* <p>
* Any {@link InMemoryGenerator} may be used to produce {@linkplain jakarta.persistence.Id
* identifiers}. The built-in identifier generators all implement the older extension point
* {@link org.hibernate.id.IdentifierGenerator}, which is a subtype of this interface, but that
* is no longer a requirement for custom id generators.
*
* @author Steve Ebersole
*

View File

@ -11,7 +11,6 @@ import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
@ -44,7 +43,7 @@ public final class PropertyFactory {
*/
public static IdentifierProperty buildIdentifierAttribute(
PersistentClass mappedEntity,
IdentifierGenerator generator) {
InMemoryGenerator generator) {
Type type = mappedEntity.getIdentifier().getType();
Property property = mappedEntity.getIdentifierProperty();

View File

@ -11,11 +11,15 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* A value generator that can adapt to both Java value generation and database value
* generation.
* A value generator that can adapt to both Java value generation and database value generation.
* <p>
* This is an older API that predates {@link Generator}. It's often cleaner to implement either
* {@link InMemoryGenerator} or {@link InDatabaseGenerator} directly.
*
* @author Steve Ebersole
* @author Gavin King
*
* @see AnnotationValueGeneration
*/
public interface ValueGeneration extends InMemoryGenerator, InDatabaseGenerator {
/**

View File

@ -158,7 +158,7 @@ public class EntityMetamodel implements Serializable {
identifierAttribute = PropertyFactory.buildIdentifierAttribute(
persistentClass,
sessionFactory.getIdentifierGenerator( rootName )
sessionFactory.getGenerator( rootName )
);
versioned = persistentClass.isVersioned();

View File

@ -37,10 +37,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

View File

@ -36,9 +36,9 @@ public class BasicForcedTableSequenceTest {
final EntityPersister persister = scope.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor(Entity.class.getName());
assertThat( persister.getIdentifierGenerator(), instanceOf( SequenceStyleGenerator.class ) );
assertThat( persister.getGenerator(), instanceOf( SequenceStyleGenerator.class ) );
final SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
final SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getGenerator();
assertThat( generator.getDatabaseStructure(), instanceOf( TableStructure.class ) );
assertThat( generator.getOptimizer(), instanceOf( NoopOptimizer.class ) );

View File

@ -40,9 +40,9 @@ public class BasicSequenceTest {
final EntityPersister persister = scope.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor(Entity.class.getName());
assertThat( persister.getIdentifierGenerator(), instanceOf( SequenceStyleGenerator.class ) );
assertThat( persister.getGenerator(), instanceOf( SequenceStyleGenerator.class ) );
final SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getIdentifierGenerator();
final SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getGenerator();
final int count = 5;
@ -71,9 +71,9 @@ public class BasicSequenceTest {
final EntityPersister persister = scope.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor(overriddenEntityName);
assertThat( persister.getIdentifierGenerator(), instanceOf( SequenceStyleGenerator.class ) );
assertThat( persister.getGenerator(), instanceOf( SequenceStyleGenerator.class ) );
final SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getIdentifierGenerator();
final SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getGenerator();
assertEquals( "ID_SEQ_BSC_ENTITY" + SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX,
generator.getDatabaseStructure().getPhysicalName().render() );

View File

@ -29,9 +29,9 @@ public class BasicTableTest {
final EntityPersister persister = scope.getSessionFactory()
.getMappingMetamodel()
.getEntityDescriptor(Entity.class.getName());
assertThat( persister.getIdentifierGenerator(), instanceOf( TableGenerator.class ) );
assertThat( persister.getGenerator(), instanceOf( TableGenerator.class ) );
final TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator();
final TableGenerator generator = ( TableGenerator ) persister.getGenerator();
scope.inTransaction(
(s) -> {

View File

@ -39,7 +39,6 @@ import org.hibernate.resource.beans.container.spi.BeanContainer;
import org.hibernate.resource.beans.container.spi.BeanContainer.LifecycleOptions;
import org.hibernate.resource.beans.container.spi.ContainedBean;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.BaseUnitTest;