HHH-18620 - Add @NativeGenerator
This commit is contained in:
parent
fccbb8d582
commit
df405d37ab
|
@ -51,6 +51,7 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
@ -283,10 +284,9 @@ public class CacheDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "identity";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.IDENTITY;
|
||||
}
|
||||
|
||||
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -75,6 +75,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
@ -654,8 +655,8 @@ public class CockroachLegacyDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,6 +100,7 @@ import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
@ -962,8 +963,8 @@ public class OracleLegacyDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
// features which change between 8i, 9i, and 10g ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -93,6 +93,7 @@ import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
@ -894,8 +895,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PACKAGE;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Generator that picks a strategy based on the {@linkplain Dialect#getNativeValueGenerationStrategy() dialect}.
|
||||
*
|
||||
* @since 7.0
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Target({METHOD, FIELD, TYPE, PACKAGE})
|
||||
@Retention(RUNTIME)
|
||||
@IdGeneratorType(org.hibernate.id.NativeGenerator.class)
|
||||
@Incubating
|
||||
public @interface NativeGenerator {
|
||||
SequenceGenerator sequenceForm() default @SequenceGenerator();
|
||||
TableGenerator tableForm() default @TableGenerator();
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.boot.model.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.models.spi.AnnotationTarget;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleIdGeneratorType;
|
||||
import static org.hibernate.boot.model.internal.GeneratorParameters.identityTablesString;
|
||||
import static org.hibernate.boot.model.internal.GeneratorStrategies.mapLegacyNamedGenerator;
|
||||
import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME;
|
||||
import static org.hibernate.id.IdentifierGenerator.JPA_ENTITY_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.IMPLICIT_NAME_BASE;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.PK;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.TABLE;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.TABLES;
|
||||
|
||||
/**
|
||||
* Template support for IdGeneratorResolver implementations dealing with entity identifiers
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractEntityIdGeneratorResolver implements IdGeneratorResolver {
|
||||
protected final PersistentClass entityMapping;
|
||||
protected final SimpleValue idValue;
|
||||
protected final MemberDetails idMember;
|
||||
protected final GeneratedValue generatedValue;
|
||||
protected final MetadataBuildingContext buildingContext;
|
||||
|
||||
public AbstractEntityIdGeneratorResolver(
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
GeneratedValue generatedValue,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.entityMapping = entityMapping;
|
||||
this.idValue = idValue;
|
||||
this.idMember = idMember;
|
||||
this.generatedValue = generatedValue;
|
||||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
switch ( generatedValue.strategy() ) {
|
||||
case UUID -> GeneratorAnnotationHelper.handleUuidStrategy( idValue, idMember, buildingContext );
|
||||
case IDENTITY -> GeneratorAnnotationHelper.handleIdentityStrategy( idValue );
|
||||
case SEQUENCE -> handleSequenceStrategy();
|
||||
case TABLE -> handleTableStrategy();
|
||||
case AUTO -> handleAutoStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSequenceStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedSequenceGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedSequenceGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void handleUnnamedSequenceGenerator();
|
||||
|
||||
protected abstract void handleNamedSequenceGenerator();
|
||||
|
||||
private void handleTableStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedTableGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedTableGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void handleUnnamedTableGenerator();
|
||||
|
||||
protected abstract void handleNamedTableGenerator();
|
||||
|
||||
private void handleAutoStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedAutoGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedAutoGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void handleUnnamedAutoGenerator();
|
||||
|
||||
protected abstract void handleNamedAutoGenerator();
|
||||
|
||||
protected boolean handleAsMetaAnnotated() {
|
||||
final Annotation fromMember = findGeneratorAnnotation( idMember );
|
||||
if ( fromMember != null ) {
|
||||
handleIdGeneratorType( fromMember, idValue, idMember, buildingContext );
|
||||
return true;
|
||||
}
|
||||
|
||||
final Annotation fromClass = findGeneratorAnnotation( idMember.getDeclaringType() );
|
||||
if ( fromClass != null ) {
|
||||
handleIdGeneratorType( fromClass, idValue, idMember, buildingContext );
|
||||
return true;
|
||||
}
|
||||
|
||||
final ClassDetails packageInfoDetails = GeneratorAnnotationHelper.locatePackageInfoDetails( idMember.getDeclaringType(), buildingContext );
|
||||
if ( packageInfoDetails != null ) {
|
||||
final Annotation fromPackage = findGeneratorAnnotation( packageInfoDetails );
|
||||
if ( fromPackage != null ) {
|
||||
handleIdGeneratorType( fromPackage, idValue, idMember, buildingContext );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Annotation findGeneratorAnnotation(AnnotationTarget annotationTarget) {
|
||||
final List<? extends Annotation> metaAnnotated = annotationTarget.getMetaAnnotated( IdGeneratorType.class, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
|
||||
if ( CollectionHelper.size( metaAnnotated ) > 0 ) {
|
||||
return metaAnnotated.get( 0 );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean handleAsLegacyGenerator() {
|
||||
// Handle a few legacy Hibernate generators...
|
||||
final String nameFromGeneratedValue = generatedValue.generator();
|
||||
if ( !nameFromGeneratedValue.isEmpty() ) {
|
||||
final Class<? extends Generator> legacyNamedGenerator = mapLegacyNamedGenerator( nameFromGeneratedValue, idValue );
|
||||
if ( legacyNamedGenerator != null ) {
|
||||
final Map<String,String> configuration = buildLegacyGeneratorConfig();
|
||||
//noinspection unchecked,rawtypes
|
||||
GeneratorBinder.createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( nameFromGeneratedValue, legacyNamedGenerator.getName(), configuration ),
|
||||
idValue,
|
||||
(Map) configuration,
|
||||
buildingContext
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private HashMap<String, String> buildLegacyGeneratorConfig() {
|
||||
final Database database = buildingContext.getMetadataCollector().getDatabase();
|
||||
final Dialect dialect = database.getDialect();
|
||||
|
||||
final HashMap<String, String> configuration = new HashMap<>();
|
||||
|
||||
final String tableName = idValue.getTable().getQuotedName( dialect );
|
||||
configuration.put( TABLE, tableName );
|
||||
|
||||
final Column idColumn = (Column) idValue.getSelectables().get( 0);
|
||||
final String idColumnName = idColumn.getQuotedName( dialect );
|
||||
configuration.put( PK, idColumnName );
|
||||
|
||||
configuration.put( ENTITY_NAME, entityMapping.getEntityName() );
|
||||
configuration.put( JPA_ENTITY_NAME, entityMapping.getJpaEntityName() );
|
||||
|
||||
// The table name is not really a good default for subselect entities,
|
||||
// so use the JPA entity name which is short
|
||||
configuration.put(
|
||||
IMPLICIT_NAME_BASE,
|
||||
idValue.getTable().isSubselect()
|
||||
? entityMapping.getJpaEntityName()
|
||||
: idValue.getTable().getName()
|
||||
);
|
||||
|
||||
configuration.put( TABLES, identityTablesString( dialect, entityMapping.getRootClass() ) );
|
||||
|
||||
return configuration;
|
||||
}
|
||||
}
|
|
@ -8,33 +8,46 @@ import java.lang.annotation.Annotation;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||
import org.hibernate.boot.models.HibernateAnnotations;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.generator.AnnotationBasedGenerator;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.GeneratorCreationContext;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.uuid.UuidGenerator;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.models.spi.AnnotationDescriptor;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.ClassDetailsRegistry;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.models.spi.SourceModelContext;
|
||||
import org.hibernate.resource.beans.container.spi.BeanContainer;
|
||||
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorParameters.collectBaselineProperties;
|
||||
import static org.hibernate.boot.model.internal.GeneratorParameters.fallbackAllocationSize;
|
||||
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.INCREMENT_PARAM;
|
||||
import static org.hibernate.internal.util.config.ConfigurationHelper.setIfNotEmpty;
|
||||
|
||||
/**
|
||||
|
@ -92,13 +105,9 @@ public class GeneratorAnnotationHelper {
|
|||
}
|
||||
|
||||
// lastly, on the package
|
||||
final String packageInfoFqn = StringHelper.qualifier( idMember.getDeclaringType().getClassName() ) + ".package-info";
|
||||
try {
|
||||
final ClassDetails packageInfo =
|
||||
context.getMetadataCollector()
|
||||
.getSourceModelBuildingContext()
|
||||
.getClassDetailsRegistry()
|
||||
.resolveClassDetails( packageInfoFqn );
|
||||
final ClassDetails packageInfo = locatePackageInfoDetails( idMember.getDeclaringType(), context );
|
||||
if ( packageInfo !=
|
||||
null ) {
|
||||
for ( A generatorAnnotation : packageInfo.getRepeatedAnnotationUsages( generatorAnnotationType, sourceModelContext ) ) {
|
||||
if ( nameExtractor != null ) {
|
||||
final String registrationName = nameExtractor.apply( generatorAnnotation );
|
||||
|
@ -118,13 +127,178 @@ public class GeneratorAnnotationHelper {
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (ClassLoadingException e) {
|
||||
// means there is no package-info
|
||||
}
|
||||
|
||||
return possibleMatch;
|
||||
}
|
||||
|
||||
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, MetadataBuildingContext buildingContext) {
|
||||
return locatePackageInfoDetails( classDetails, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
|
||||
}
|
||||
|
||||
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, SourceModelContext modelContext) {
|
||||
return locatePackageInfoDetails( classDetails, modelContext.getClassDetailsRegistry() );
|
||||
}
|
||||
|
||||
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, ClassDetailsRegistry classDetailsRegistry) {
|
||||
final String packageInfoFqn = StringHelper.qualifier( classDetails.getName() ) + ".package-info";
|
||||
try {
|
||||
return classDetailsRegistry.resolveClassDetails( packageInfoFqn );
|
||||
}
|
||||
catch (ClassLoadingException e) {
|
||||
// means there is no package-info
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleSequenceGenerator(
|
||||
String nameFromGeneratedValue,
|
||||
SequenceGenerator generatorAnnotation,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final SequenceStyleGenerator identifierGenerator = GeneratorBinder.instantiateGenerator(
|
||||
beanContainer,
|
||||
SequenceStyleGenerator.class
|
||||
);
|
||||
prepareForUse(
|
||||
identifierGenerator,
|
||||
generatorAnnotation,
|
||||
idMember,
|
||||
properties -> {
|
||||
if ( generatorAnnotation != null ) {
|
||||
properties.put( GENERATOR_NAME, generatorAnnotation.name() );
|
||||
}
|
||||
else if ( nameFromGeneratedValue != null ) {
|
||||
properties.put( GENERATOR_NAME, nameFromGeneratedValue );
|
||||
}
|
||||
// we need to better handle default allocation-size here...
|
||||
properties.put( INCREMENT_PARAM, fallbackAllocationSize( generatorAnnotation, buildingContext ) );
|
||||
},
|
||||
generatorAnnotation == null
|
||||
? null
|
||||
: (a, properties) -> SequenceStyleGenerator.applyConfiguration( generatorAnnotation, properties::put ),
|
||||
creationContext
|
||||
);
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
|
||||
public static void handleTableGenerator(
|
||||
String nameFromGeneratedValue,
|
||||
TableGenerator generatorAnnotation,
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final org.hibernate.id.enhanced.TableGenerator identifierGenerator = GeneratorBinder.instantiateGenerator(
|
||||
beanContainer,
|
||||
org.hibernate.id.enhanced.TableGenerator.class
|
||||
);
|
||||
GeneratorAnnotationHelper.prepareForUse(
|
||||
identifierGenerator,
|
||||
generatorAnnotation,
|
||||
idMember,
|
||||
properties -> {
|
||||
if ( generatorAnnotation != null ) {
|
||||
properties.put( GENERATOR_NAME, generatorAnnotation.name() );
|
||||
}
|
||||
else if ( nameFromGeneratedValue != null ) {
|
||||
properties.put( GENERATOR_NAME, nameFromGeneratedValue );
|
||||
}
|
||||
// we need to better handle default allocation-size here...
|
||||
properties.put(
|
||||
INCREMENT_PARAM,
|
||||
fallbackAllocationSize( generatorAnnotation, buildingContext )
|
||||
);
|
||||
},
|
||||
generatorAnnotation == null
|
||||
? null
|
||||
: (a, properties) -> org.hibernate.id.enhanced.TableGenerator.applyConfiguration(
|
||||
generatorAnnotation,
|
||||
properties::put
|
||||
),
|
||||
creationContext
|
||||
);
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
|
||||
public static void handleIdGeneratorType(
|
||||
Annotation generatorAnnotation,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final IdGeneratorType markerAnnotation = generatorAnnotation.annotationType().getAnnotation( IdGeneratorType.class );
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final Generator identifierGenerator = GeneratorBinder.instantiateGenerator(
|
||||
beanContainer,
|
||||
markerAnnotation.value()
|
||||
);
|
||||
GeneratorAnnotationHelper.prepareForUse(
|
||||
identifierGenerator,
|
||||
generatorAnnotation,
|
||||
idMember,
|
||||
null,
|
||||
null,
|
||||
creationContext
|
||||
);
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a generator for use by handling its various potential means of "configuration".
|
||||
*
|
||||
* @param generator The "empty" generator
|
||||
* @param annotation The annotation which defines configuration for the generator
|
||||
* @param idMember The member defining the id
|
||||
* @param configBaseline Allows to set any default values. Called before common config is handled.
|
||||
* @param configExtractor Allows to extract values from the generator annotation. Called after common config is handled.
|
||||
* @param creationContext Access to useful information
|
||||
*/
|
||||
public static <A extends Annotation> void prepareForUse(
|
||||
Generator generator,
|
||||
A annotation,
|
||||
MemberDetails idMember,
|
||||
Consumer<Properties> configBaseline,
|
||||
BiConsumer<A,Properties> configExtractor,
|
||||
GeneratorCreationContext creationContext) {
|
||||
if ( generator instanceof AnnotationBasedGenerator ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final AnnotationBasedGenerator<A> generation = (AnnotationBasedGenerator<A>) generator;
|
||||
generation.initialize( annotation, idMember.toJavaMember(), creationContext );
|
||||
}
|
||||
if ( generator instanceof Configurable configurable ) {
|
||||
final Properties properties = new Properties();
|
||||
if ( configBaseline != null ) {
|
||||
configBaseline.accept( properties );
|
||||
}
|
||||
collectBaselineProperties(
|
||||
creationContext.getProperty() != null
|
||||
? (SimpleValue) creationContext.getProperty().getValue()
|
||||
: (SimpleValue) creationContext.getPersistentClass().getIdentifierProperty().getValue(),
|
||||
creationContext.getDatabase().getDialect(),
|
||||
creationContext.getRootClass(),
|
||||
properties::setProperty
|
||||
);
|
||||
if ( configExtractor != null ) {
|
||||
configExtractor.accept( annotation, properties );
|
||||
}
|
||||
configurable.configure( creationContext, properties );
|
||||
}
|
||||
if ( generator instanceof ExportableProducer exportableProducer ) {
|
||||
exportableProducer.registerExportables( creationContext.getDatabase() );
|
||||
}
|
||||
if ( generator instanceof Configurable configurable ) {
|
||||
configurable.initialize( creationContext.getSqlStringGenerationContext() );
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleUuidStrategy(
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
|
@ -144,44 +318,6 @@ public class GeneratorAnnotationHelper {
|
|||
idValue.setColumnToIdentity();
|
||||
}
|
||||
|
||||
public static void applyBaselineConfiguration(
|
||||
SequenceGenerator generatorConfig,
|
||||
SimpleValue idValue,
|
||||
RootClass rootClass,
|
||||
MetadataBuildingContext context,
|
||||
BiConsumer<String,String> configurationCollector) {
|
||||
if ( generatorConfig != null && !generatorConfig.name().isEmpty() ) {
|
||||
configurationCollector.accept( GENERATOR_NAME, generatorConfig.name() );
|
||||
}
|
||||
|
||||
GeneratorParameters.collectParameters(
|
||||
idValue,
|
||||
context.getMetadataCollector().getDatabase().getDialect(),
|
||||
rootClass,
|
||||
configurationCollector
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static void applyBaselineConfiguration(
|
||||
TableGenerator generatorConfig,
|
||||
SimpleValue idValue,
|
||||
RootClass rootClass,
|
||||
MetadataBuildingContext context,
|
||||
BiConsumer<String, String> configurationCollector) {
|
||||
if ( !generatorConfig.name().isEmpty() ) {
|
||||
configurationCollector.accept( GENERATOR_NAME, generatorConfig.name() );
|
||||
}
|
||||
|
||||
GeneratorParameters.collectParameters(
|
||||
idValue,
|
||||
context.getMetadataCollector().getDatabase().getDialect(),
|
||||
rootClass,
|
||||
configurationCollector
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public static void handleGenericGenerator(
|
||||
String generatorName,
|
||||
GenericGenerator generatorConfig,
|
||||
|
@ -221,22 +357,4 @@ public class GeneratorAnnotationHelper {
|
|||
configuration.put( parameter.name(), parameter.value() );
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleTableGenerator(
|
||||
String generatorName,
|
||||
TableGenerator generatorConfig,
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MetadataBuildingContext context) {
|
||||
final Map<String,String> configuration = new HashMap<>();
|
||||
applyBaselineConfiguration( generatorConfig, idValue, entityMapping.getRootClass(), context, configuration::put );
|
||||
org.hibernate.id.enhanced.TableGenerator.applyConfiguration( generatorConfig, configuration::put );
|
||||
|
||||
GeneratorBinder.createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( generatorName, org.hibernate.id.enhanced.TableGenerator.class.getName(), configuration ),
|
||||
idValue,
|
||||
context
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -536,9 +536,9 @@ public class GeneratorBinder {
|
|||
* @param beanContainer an optional {@code BeanContainer}
|
||||
* @param generatorClass a class which implements {@code Generator}
|
||||
*/
|
||||
private static Generator instantiateGeneratorAsBean(
|
||||
private static <T extends Generator> T instantiateGeneratorAsBean(
|
||||
BeanContainer beanContainer,
|
||||
Class<? extends Generator> generatorClass) {
|
||||
Class<T> generatorClass) {
|
||||
return beanContainer.getBean( generatorClass,
|
||||
new BeanContainer.LifecycleOptions() {
|
||||
@Override
|
||||
|
@ -611,9 +611,9 @@ public class GeneratorBinder {
|
|||
* @param beanContainer an optional {@code BeanContainer}
|
||||
* @param generatorClass a class which implements {@code Generator}
|
||||
*/
|
||||
public static Generator instantiateGenerator(
|
||||
public static <T extends Generator> T instantiateGenerator(
|
||||
BeanContainer beanContainer,
|
||||
Class<? extends Generator> generatorClass) {
|
||||
Class<T> generatorClass) {
|
||||
if ( beanContainer != null ) {
|
||||
return instantiateGeneratorAsBean( beanContainer, generatorClass );
|
||||
}
|
||||
|
@ -637,7 +637,7 @@ public class GeneratorBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static <A extends Annotation> void callInitialize(
|
||||
public static <A extends Annotation> void callInitialize(
|
||||
A annotation,
|
||||
MemberDetails memberDetails,
|
||||
GeneratorCreationContext creationContext,
|
||||
|
@ -725,6 +725,7 @@ public class GeneratorBinder {
|
|||
persistentClass,
|
||||
idValue,
|
||||
idMember,
|
||||
generatedValue,
|
||||
context
|
||||
) );
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.internal;
|
||||
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
|
@ -30,10 +32,11 @@ import org.hibernate.mapping.RootClass;
|
|||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.BiConsumer;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
|
||||
import static org.hibernate.cfg.MappingSettings.ID_DB_STRUCTURE_NAMING_STRATEGY;
|
||||
import static org.hibernate.id.IdentifierGenerator.CONTRIBUTOR_NAME;
|
||||
import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME;
|
||||
import static org.hibernate.id.IdentifierGenerator.JPA_ENTITY_NAME;
|
||||
|
@ -93,15 +96,49 @@ public class GeneratorParameters {
|
|||
RootClass rootClass,
|
||||
BiConsumer<String,String> parameterCollector) {
|
||||
|
||||
final ConfigurationService configService =
|
||||
identifierValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry()
|
||||
final ConfigurationService configService = identifierValue
|
||||
.getMetadata()
|
||||
.getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
|
||||
|
||||
// default initial value and allocation size per-JPA defaults
|
||||
parameterCollector.accept( INITIAL_PARAM, String.valueOf( DEFAULT_INITIAL_VALUE ) );
|
||||
parameterCollector.accept( INCREMENT_PARAM, String.valueOf( defaultIncrement( configService ) ) );
|
||||
|
||||
collectBaselineProperties( identifierValue, dialect, rootClass, parameterCollector );
|
||||
}
|
||||
|
||||
public static int fallbackAllocationSize(Annotation generatorAnnotation, MetadataBuildingContext buildingContext) {
|
||||
if ( generatorAnnotation == null ) {
|
||||
final ConfigurationService configService = buildingContext
|
||||
.getBootstrapContext()
|
||||
.getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
final String idNamingStrategy = configService.getSetting( ID_DB_STRUCTURE_NAMING_STRATEGY, StandardConverters.STRING );
|
||||
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return OptimizableGenerator.DEFAULT_INCREMENT_SIZE;
|
||||
}
|
||||
|
||||
public static void collectBaselineProperties(
|
||||
SimpleValue identifierValue,
|
||||
Dialect dialect,
|
||||
RootClass rootClass,
|
||||
BiConsumer<String,String> parameterCollector) {
|
||||
|
||||
final ConfigurationService configService = identifierValue
|
||||
.getMetadata()
|
||||
.getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
|
||||
//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
|
||||
|
@ -144,6 +181,7 @@ public class GeneratorParameters {
|
|||
(String) settings.get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER )
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String identityTablesString(Dialect dialect, RootClass rootClass) {
|
||||
|
@ -157,10 +195,6 @@ public class GeneratorParameters {
|
|||
return tables.toString();
|
||||
}
|
||||
|
||||
public static int defaultIncrement(MetadataImplementor metadata) {
|
||||
return defaultIncrement( metadata.getMetadataBuildingOptions().getServiceRegistry().requireService( ConfigurationService.class ) );
|
||||
}
|
||||
|
||||
public static int defaultIncrement(ConfigurationService configService) {
|
||||
final String idNamingStrategy =
|
||||
configService.getSetting( AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
|
||||
|
|
|
@ -24,14 +24,17 @@ import org.hibernate.mapping.IdentifierBag;
|
|||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.resource.beans.container.spi.BeanContainer;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.applyBaselineConfiguration;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.createGeneratorFrom;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorParameters.fallbackAllocationSize;
|
||||
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.INCREMENT_PARAM;
|
||||
|
||||
/**
|
||||
* IdGeneratorResolver for handling generators assigned to id-bag mappings
|
||||
|
@ -41,7 +44,7 @@ import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator;
|
|||
public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
||||
private final PersistentClass entityMapping;
|
||||
private final SimpleValue idValue;
|
||||
private final MemberDetails idAttributeMember;
|
||||
private final MemberDetails idBagMember;
|
||||
private final String generatorType;
|
||||
private final String generatorName;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
|
@ -50,13 +53,13 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
public IdBagIdGeneratorResolverSecondPass(
|
||||
IdentifierBag idBagMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idAttributeMember,
|
||||
MemberDetails idBagMember,
|
||||
String generatorType,
|
||||
String generatorName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.entityMapping = null;
|
||||
this.idValue = idValue;
|
||||
this.idAttributeMember = idAttributeMember;
|
||||
this.idBagMember = idBagMember;
|
||||
this.generatorType = generatorType;
|
||||
this.generatorName = generatorName;
|
||||
this.buildingContext = buildingContext;
|
||||
|
@ -66,27 +69,27 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> idGeneratorDefinitionMap) throws MappingException {
|
||||
final GeneratedValue generatedValue = idAttributeMember.getDirectAnnotationUsage( GeneratedValue.class );
|
||||
final GeneratedValue generatedValue = idBagMember.getDirectAnnotationUsage( GeneratedValue.class );
|
||||
switch ( generatedValue.strategy() ) {
|
||||
case UUID -> GeneratorAnnotationHelper.handleUuidStrategy( idValue, idAttributeMember, buildingContext );
|
||||
case UUID -> GeneratorAnnotationHelper.handleUuidStrategy( idValue, idBagMember, buildingContext );
|
||||
case IDENTITY -> GeneratorAnnotationHelper.handleIdentityStrategy( idValue );
|
||||
case SEQUENCE -> handleSequenceStrategy(
|
||||
generatorName,
|
||||
idValue,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
case TABLE -> handleTableStrategy(
|
||||
generatorName,
|
||||
entityMapping,
|
||||
idValue,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
case AUTO -> handleAutoStrategy(
|
||||
generatorName,
|
||||
idValue,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
String generatorName,
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idAttributeMember,
|
||||
MemberDetails idBagMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
final GlobalRegistrations globalRegistrations = metadataCollector.getGlobalRegistrations();
|
||||
|
@ -107,8 +110,8 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
handleTableGenerator(
|
||||
generatorName,
|
||||
globalTableGenerator.configuration(),
|
||||
configuration,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -116,13 +119,13 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
|
||||
final TableGenerator localizedTableMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
TableGenerator::name,
|
||||
generatorName,
|
||||
buildingContext
|
||||
);
|
||||
if ( localizedTableMatch != null ) {
|
||||
handleTableGenerator( generatorName, localizedTableMatch, configuration, idValue, buildingContext );
|
||||
handleTableGenerator( generatorName, localizedTableMatch, idValue, idBagMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -131,6 +134,7 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
new TableGeneratorJpaAnnotation( metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
@ -138,7 +142,7 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
private void handleSequenceStrategy(
|
||||
String generatorName,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idAttributeMember,
|
||||
MemberDetails idBagMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
final GlobalRegistrations globalRegistrations = metadataCollector.getGlobalRegistrations();
|
||||
|
@ -149,8 +153,8 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
handleSequenceGenerator(
|
||||
generatorName,
|
||||
globalSequenceGenerator.configuration(),
|
||||
configuration,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -158,21 +162,21 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
|
||||
final SequenceGenerator localizedSequencedMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
SequenceGenerator::name,
|
||||
generatorName,
|
||||
buildingContext
|
||||
);
|
||||
if ( localizedSequencedMatch != null ) {
|
||||
handleSequenceGenerator( generatorName, localizedSequencedMatch, configuration, idValue, buildingContext );
|
||||
handleSequenceGenerator( generatorName, localizedSequencedMatch, idValue, idBagMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
handleSequenceGenerator(
|
||||
generatorName,
|
||||
new SequenceGeneratorJpaAnnotation( metadataCollector.getSourceModelBuildingContext() ),
|
||||
configuration,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
@ -180,7 +184,7 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
private void handleAutoStrategy(
|
||||
String generatorName,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idAttributeMember,
|
||||
MemberDetails idBagMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final GlobalRegistrations globalRegistrations =
|
||||
buildingContext.getMetadataCollector().getGlobalRegistrations();
|
||||
|
@ -191,8 +195,8 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
handleSequenceGenerator(
|
||||
generatorName,
|
||||
globalSequenceGenerator.configuration(),
|
||||
configuration,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -204,8 +208,8 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
handleTableGenerator(
|
||||
generatorName,
|
||||
globalTableGenerator.configuration(),
|
||||
configuration,
|
||||
idValue,
|
||||
idBagMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -230,62 +234,98 @@ public class IdBagIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
|
||||
final SequenceGenerator localizedSequencedMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
SequenceGenerator::name,
|
||||
generatorName,
|
||||
buildingContext
|
||||
);
|
||||
if ( localizedSequencedMatch != null ) {
|
||||
handleSequenceGenerator( generatorName, localizedSequencedMatch, configuration, idValue, buildingContext );
|
||||
handleSequenceGenerator( generatorName, localizedSequencedMatch, idValue, idBagMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
final TableGenerator localizedTableMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idAttributeMember,
|
||||
idBagMember,
|
||||
TableGenerator::name,
|
||||
generatorName,
|
||||
buildingContext
|
||||
);
|
||||
if ( localizedTableMatch != null ) {
|
||||
handleTableGenerator( generatorName, localizedTableMatch, configuration, idValue, buildingContext );
|
||||
handleTableGenerator( generatorName, localizedTableMatch, idValue, idBagMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
makeIdGenerator( idValue, idAttributeMember, generatorType, generatorName, buildingContext, null );
|
||||
makeIdGenerator( idValue, idBagMember, generatorType, generatorName, buildingContext, null );
|
||||
}
|
||||
|
||||
public static void handleSequenceGenerator(
|
||||
String generatorName,
|
||||
SequenceGenerator generatorConfig,
|
||||
Map<String,String> configuration,
|
||||
String nameFromGeneratedValue,
|
||||
SequenceGenerator generatorAnnotation,
|
||||
SimpleValue idValue,
|
||||
MetadataBuildingContext context) {
|
||||
applyBaselineConfiguration( generatorConfig, idValue, null, context, configuration::put );
|
||||
SequenceStyleGenerator.applyConfiguration( generatorConfig, configuration::put );
|
||||
createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( generatorName, SequenceStyleGenerator.class.getName(), configuration ),
|
||||
idValue,
|
||||
(Map) configuration,
|
||||
context
|
||||
MemberDetails idBagMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final SequenceStyleGenerator identifierGenerator = GeneratorBinder.instantiateGenerator(
|
||||
beanContainer,
|
||||
SequenceStyleGenerator.class
|
||||
);
|
||||
GeneratorAnnotationHelper.prepareForUse(
|
||||
identifierGenerator,
|
||||
generatorAnnotation,
|
||||
idBagMember,
|
||||
properties -> {
|
||||
if ( generatorAnnotation != null ) {
|
||||
properties.put( GENERATOR_NAME, generatorAnnotation.name() );
|
||||
}
|
||||
else if ( nameFromGeneratedValue != null ) {
|
||||
properties.put( GENERATOR_NAME, nameFromGeneratedValue );
|
||||
}
|
||||
// we need to better handle default allocation-size here...
|
||||
properties.put( INCREMENT_PARAM, fallbackAllocationSize( generatorAnnotation, buildingContext ) );
|
||||
},
|
||||
generatorAnnotation == null
|
||||
? null
|
||||
: (a, properties) -> SequenceStyleGenerator.applyConfiguration( generatorAnnotation, properties::put ),
|
||||
creationContext
|
||||
);
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
|
||||
public static void handleTableGenerator(
|
||||
String generatorName,
|
||||
TableGenerator generatorConfig,
|
||||
Map<String,String> configuration,
|
||||
String nameFromGeneratedValue,
|
||||
TableGenerator generatorAnnotation,
|
||||
SimpleValue idValue,
|
||||
MetadataBuildingContext context) {
|
||||
GeneratorAnnotationHelper.applyBaselineConfiguration( generatorConfig, idValue, null, context, configuration::put );
|
||||
org.hibernate.id.enhanced.TableGenerator.applyConfiguration( generatorConfig, configuration::put );
|
||||
|
||||
createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( generatorName, org.hibernate.id.enhanced.TableGenerator.class.getName(), configuration ),
|
||||
idValue,
|
||||
(Map) configuration,
|
||||
context
|
||||
MemberDetails idBagMember,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final org.hibernate.id.enhanced.TableGenerator identifierGenerator = GeneratorBinder.instantiateGenerator(
|
||||
beanContainer,
|
||||
org.hibernate.id.enhanced.TableGenerator.class
|
||||
);
|
||||
|
||||
GeneratorAnnotationHelper.prepareForUse(
|
||||
identifierGenerator,
|
||||
generatorAnnotation,
|
||||
idBagMember,
|
||||
properties -> {
|
||||
if ( generatorAnnotation != null ) {
|
||||
properties.put( GENERATOR_NAME, generatorAnnotation.name() );
|
||||
}
|
||||
else if ( nameFromGeneratedValue != null ) {
|
||||
properties.put( GENERATOR_NAME, nameFromGeneratedValue );
|
||||
}
|
||||
// we need to better handle default allocation-size here...
|
||||
properties.put( INCREMENT_PARAM, fallbackAllocationSize( generatorAnnotation, buildingContext ) );
|
||||
},
|
||||
generatorAnnotation == null
|
||||
? null
|
||||
: (a, properties) -> org.hibernate.id.enhanced.TableGenerator.applyConfiguration( generatorAnnotation, properties::put ),
|
||||
creationContext
|
||||
);
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,11 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.models.HibernateAnnotations;
|
||||
import org.hibernate.boot.models.JpaAnnotations;
|
||||
|
@ -21,32 +16,19 @@ import org.hibernate.boot.models.spi.GenericGeneratorRegistration;
|
|||
import org.hibernate.boot.models.spi.GlobalRegistrations;
|
||||
import org.hibernate.boot.models.spi.SequenceGeneratorRegistration;
|
||||
import org.hibernate.boot.models.spi.TableGeneratorRegistration;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.enhanced.LegacyNamingStrategy;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.enhanced.SingleNamingStrategy;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.resource.beans.container.spi.BeanContainer;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.TableGenerator;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.callConfigure;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.instantiateGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.findLocalizedMatch;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleSequenceGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorStrategies.mapLegacyNamedGenerator;
|
||||
import static org.hibernate.cfg.MappingSettings.ID_DB_STRUCTURE_NAMING_STRATEGY;
|
||||
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.INCREMENT_PARAM;
|
||||
|
||||
/**
|
||||
* SecondPass implementing delayed resolution of id-generators associated with an entity.
|
||||
|
@ -55,50 +37,25 @@ import static org.hibernate.id.OptimizableGenerator.INCREMENT_PARAM;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
||||
private final PersistentClass entityMapping;
|
||||
private final SimpleValue idValue;
|
||||
private final MemberDetails idMember;
|
||||
private final GeneratedValue generatedValue;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
|
||||
public class IdGeneratorResolverSecondPass extends AbstractEntityIdGeneratorResolver {
|
||||
public IdGeneratorResolverSecondPass(
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
GeneratedValue generatedValue,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.entityMapping = entityMapping;
|
||||
this.idValue = idValue;
|
||||
this.idMember = idMember;
|
||||
this.generatedValue = generatedValue;
|
||||
this.buildingContext = buildingContext;
|
||||
super( entityMapping, idValue, idMember, generatedValue, buildingContext );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// SEQUENCE
|
||||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
switch ( generatedValue.strategy() ) {
|
||||
case UUID -> GeneratorAnnotationHelper.handleUuidStrategy( idValue, idMember, buildingContext );
|
||||
case IDENTITY -> GeneratorAnnotationHelper.handleIdentityStrategy( idValue );
|
||||
case SEQUENCE -> handleSequenceStrategy();
|
||||
case TABLE -> handleTableStrategy();
|
||||
case AUTO -> handleAutoStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSequenceStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedSequenceGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedSequenceGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnnamedSequenceGenerator() {
|
||||
protected void handleUnnamedSequenceGenerator() {
|
||||
// todo (7.0) : null or entityMapping.getJpaEntityName() for "name from GeneratedValue"?
|
||||
|
||||
final SequenceGenerator localizedMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final SequenceGenerator localizedMatch = findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idMember,
|
||||
null,
|
||||
|
@ -106,17 +63,18 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
buildingContext
|
||||
);
|
||||
if ( localizedMatch != null ) {
|
||||
handleSequenceGenerator( null, localizedMatch );
|
||||
handleSequenceGenerator( null, localizedMatch, idValue, idMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
handleSequenceGenerator( null, null );
|
||||
handleSequenceGenerator( null, null, idValue, idMember, buildingContext );
|
||||
}
|
||||
|
||||
private void handleNamedSequenceGenerator() {
|
||||
@Override
|
||||
protected void handleNamedSequenceGenerator() {
|
||||
final String generator = generatedValue.generator();
|
||||
|
||||
final SequenceGenerator localizedMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final SequenceGenerator localizedMatch = findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idMember,
|
||||
SequenceGenerator::name,
|
||||
|
@ -124,7 +82,7 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
buildingContext
|
||||
);
|
||||
if ( localizedMatch != null ) {
|
||||
handleSequenceGenerator( generator, localizedMatch );
|
||||
handleSequenceGenerator( generator, localizedMatch, idValue, idMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -135,13 +93,13 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
.getSequenceGeneratorRegistrations()
|
||||
.get( generator );
|
||||
if ( globalMatch != null ) {
|
||||
handleSequenceGenerator( generator, globalMatch.configuration() );
|
||||
handleSequenceGenerator( generator, globalMatch.configuration(), idValue, idMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
validateSequenceGeneration();
|
||||
|
||||
handleSequenceGenerator( generator, null );
|
||||
handleSequenceGenerator( generator, null, idValue, idMember, buildingContext );
|
||||
}
|
||||
|
||||
private void validateSequenceGeneration() {
|
||||
|
@ -178,19 +136,15 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleTableStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedTableGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedTableGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnnamedTableGenerator() {
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// TABLE
|
||||
|
||||
@Override
|
||||
protected void handleUnnamedTableGenerator() {
|
||||
// todo (7.0) : null or entityMapping.getJpaEntityName() for "name from GeneratedValue"?
|
||||
|
||||
final TableGenerator localizedMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final TableGenerator localizedMatch = findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idMember,
|
||||
null,
|
||||
|
@ -200,10 +154,11 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
handleTableGenerator( null, localizedMatch );
|
||||
}
|
||||
|
||||
private void handleNamedTableGenerator() {
|
||||
@Override
|
||||
protected void handleNamedTableGenerator() {
|
||||
final String generator = generatedValue.generator();
|
||||
|
||||
final TableGenerator localizedTableMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final TableGenerator localizedTableMatch = findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idMember,
|
||||
TableGenerator::name,
|
||||
|
@ -263,19 +218,15 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleAutoStrategy() {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedAutoGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedAutoGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnnamedAutoGenerator() {
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUTO
|
||||
|
||||
@Override
|
||||
protected void handleUnnamedAutoGenerator() {
|
||||
// todo (7.0) : null or entityMapping.getJpaEntityName() for "name from GeneratedValue"?
|
||||
|
||||
final SequenceGenerator localizedSequenceMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final SequenceGenerator localizedSequenceMatch = findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idMember,
|
||||
null,
|
||||
|
@ -283,11 +234,11 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
buildingContext
|
||||
);
|
||||
if ( localizedSequenceMatch != null ) {
|
||||
handleSequenceGenerator( null, localizedSequenceMatch );
|
||||
handleSequenceGenerator( null, localizedSequenceMatch, idValue, idMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
final TableGenerator localizedTableMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final TableGenerator localizedTableMatch = findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idMember,
|
||||
null,
|
||||
|
@ -299,7 +250,7 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return;
|
||||
}
|
||||
|
||||
final GenericGenerator localizedGenericMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final GenericGenerator localizedGenericMatch = findLocalizedMatch(
|
||||
HibernateAnnotations.GENERIC_GENERATOR,
|
||||
idMember,
|
||||
null,
|
||||
|
@ -317,16 +268,25 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( handleAsMetaAnnotated() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( idMember.getType().isImplementor( UUID.class )
|
||||
|| idMember.getType().isImplementor( String.class ) ) {
|
||||
GeneratorAnnotationHelper.handleUuidStrategy( idValue, idMember, buildingContext );
|
||||
return;
|
||||
}
|
||||
|
||||
handleSequenceGenerator( null, null );
|
||||
if ( handleAsLegacyGenerator() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void handleNamedAutoGenerator() {
|
||||
handleSequenceGenerator( null, null, idValue, idMember, buildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleNamedAutoGenerator() {
|
||||
if ( handleAsLocalAutoGenerator() ) {
|
||||
return;
|
||||
}
|
||||
|
@ -347,29 +307,7 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return;
|
||||
}
|
||||
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
final List<? extends Annotation> metaAnnotated =
|
||||
idMember.getMetaAnnotated( IdGeneratorType.class, metadataCollector.getSourceModelBuildingContext() );
|
||||
if ( CollectionHelper.size( metaAnnotated ) > 0 ) {
|
||||
final Annotation generatorAnnotation = metaAnnotated.get( 0 );
|
||||
final IdGeneratorType markerAnnotation = generatorAnnotation.annotationType().getAnnotation( IdGeneratorType.class );
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
final Generator identifierGenerator = instantiateGenerator(
|
||||
beanContainer,
|
||||
markerAnnotation.value()
|
||||
);
|
||||
final Map<String,Object> configuration = new HashMap<>();
|
||||
GeneratorParameters.collectParameters(
|
||||
idValue,
|
||||
metadataCollector.getDatabase().getDialect(),
|
||||
entityMapping.getRootClass(),
|
||||
configuration::put
|
||||
);
|
||||
callConfigure( creationContext, identifierGenerator, configuration, idValue );
|
||||
return identifierGenerator;
|
||||
} );
|
||||
if ( handleAsMetaAnnotated() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -379,14 +317,18 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return;
|
||||
}
|
||||
|
||||
handleSequenceGenerator(generator, null );
|
||||
if ( handleAsLegacyGenerator() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleSequenceGenerator( generator, null, idValue, idMember, buildingContext );
|
||||
}
|
||||
|
||||
private boolean handleAsLocalAutoGenerator() {
|
||||
final String generator = generatedValue.generator();
|
||||
assert !generator.isEmpty();
|
||||
|
||||
final SequenceGenerator localizedSequenceMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final SequenceGenerator localizedSequenceMatch = findLocalizedMatch(
|
||||
JpaAnnotations.SEQUENCE_GENERATOR,
|
||||
idMember,
|
||||
SequenceGenerator::name,
|
||||
|
@ -394,11 +336,11 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
buildingContext
|
||||
);
|
||||
if ( localizedSequenceMatch != null ) {
|
||||
handleSequenceGenerator( generator, localizedSequenceMatch );
|
||||
handleSequenceGenerator( generator, localizedSequenceMatch, idValue, idMember, buildingContext );
|
||||
return true;
|
||||
}
|
||||
|
||||
final TableGenerator localizedTableMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final TableGenerator localizedTableMatch = findLocalizedMatch(
|
||||
JpaAnnotations.TABLE_GENERATOR,
|
||||
idMember,
|
||||
TableGenerator::name,
|
||||
|
@ -410,7 +352,7 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return true;
|
||||
}
|
||||
|
||||
final GenericGenerator localizedGenericMatch = GeneratorAnnotationHelper.findLocalizedMatch(
|
||||
final GenericGenerator localizedGenericMatch = findLocalizedMatch(
|
||||
HibernateAnnotations.GENERIC_GENERATOR,
|
||||
idMember,
|
||||
GenericGenerator::name,
|
||||
|
@ -439,7 +381,7 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
final SequenceGeneratorRegistration globalSequenceMatch =
|
||||
globalRegistrations.getSequenceGeneratorRegistrations().get( generator );
|
||||
if ( globalSequenceMatch != null ) {
|
||||
handleSequenceGenerator( generator, globalSequenceMatch.configuration() );
|
||||
handleSequenceGenerator( generator, globalSequenceMatch.configuration(), idValue, idMember, buildingContext );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -466,97 +408,15 @@ public class IdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void handleSequenceGenerator(String nameFromGeneratedValue, SequenceGenerator generator) {
|
||||
createGeneratorFrom( SequenceStyleGenerator.class, extractConfiguration( nameFromGeneratedValue, generator ) );
|
||||
}
|
||||
|
||||
private Map<String,Object> extractConfiguration(String nameFromGenerated, SequenceGenerator generator) {
|
||||
final Map<String, Object> configuration = new HashMap<>();
|
||||
if ( generator != null ) {
|
||||
configuration.put( GENERATOR_NAME, generator.name() );
|
||||
}
|
||||
else if ( nameFromGenerated != null ) {
|
||||
configuration.put( GENERATOR_NAME, nameFromGenerated );
|
||||
}
|
||||
|
||||
applyCommonConfiguration( configuration, generator );
|
||||
|
||||
if ( generator != null ) {
|
||||
SequenceStyleGenerator.applyConfiguration( generator, configuration::put );
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private void applyCommonConfiguration(Map<String, Object> configuration, Annotation generatorAnnotation) {
|
||||
GeneratorParameters.collectParameters(
|
||||
private void handleTableGenerator(String nameFromGeneratedValue, TableGenerator generatorAnnotation) {
|
||||
GeneratorAnnotationHelper.handleTableGenerator(
|
||||
nameFromGeneratedValue,
|
||||
generatorAnnotation,
|
||||
entityMapping,
|
||||
idValue,
|
||||
buildingContext.getMetadataCollector().getDatabase().getDialect(),
|
||||
entityMapping.getRootClass(),
|
||||
configuration::put
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
|
||||
// we need to better handle default allocation-size here...
|
||||
configuration.put( INCREMENT_PARAM, fallbackAllocationSize( buildingContext, generatorAnnotation ) );
|
||||
}
|
||||
|
||||
private static int fallbackAllocationSize(MetadataBuildingContext buildingContext, Annotation generatorAnnotation) {
|
||||
if ( generatorAnnotation == null ) {
|
||||
// Special case where we have no matching SequenceGenerator/TableGenerator annotation.
|
||||
// Historically we interpreted such cases using a default of 1, but JPA says the default
|
||||
// here should be 50. As a migration aid, under the assumption that one of the legacy
|
||||
// naming-strategies are used in such cases, we revert to the old default; otherwise we
|
||||
// use the compliant value.
|
||||
final ConfigurationService configService =
|
||||
buildingContext.getBootstrapContext().getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
final String idNamingStrategy =
|
||||
configService.getSetting( ID_DB_STRUCTURE_NAMING_STRATEGY, StandardConverters.STRING );
|
||||
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return OptimizableGenerator.DEFAULT_INCREMENT_SIZE;
|
||||
}
|
||||
|
||||
private void handleTableGenerator(String nameFromGeneratedValue, TableGenerator generator) {
|
||||
createGeneratorFrom( org.hibernate.id.enhanced.TableGenerator.class,
|
||||
extractConfiguration( nameFromGeneratedValue, generator ) );
|
||||
}
|
||||
|
||||
private Map<String,Object> extractConfiguration(String nameFromGenerated, TableGenerator generator) {
|
||||
final Map<String, Object> configuration = new HashMap<>();
|
||||
if ( generator != null ) {
|
||||
configuration.put( GENERATOR_NAME, generator.name() );
|
||||
}
|
||||
else if ( nameFromGenerated != null ) {
|
||||
configuration.put( GENERATOR_NAME, nameFromGenerated );
|
||||
}
|
||||
|
||||
applyCommonConfiguration( configuration, generator );
|
||||
|
||||
if ( generator != null ) {
|
||||
org.hibernate.id.enhanced.TableGenerator.applyConfiguration( generator, configuration::put );
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private void createGeneratorFrom(
|
||||
Class<? extends Generator> generatorClass,
|
||||
Map<String, Object> configuration) {
|
||||
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
|
||||
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
|
||||
final Generator identifierGenerator = instantiateGenerator( beanContainer, generatorClass );
|
||||
callConfigure( creationContext, identifierGenerator, configuration, idValue );
|
||||
if ( identifierGenerator instanceof IdentityGenerator ) {
|
||||
idValue.setColumnToIdentity();
|
||||
}
|
||||
return identifierGenerator;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,8 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.models.annotations.internal.SequenceGeneratorJpaAnnotation;
|
||||
import org.hibernate.boot.models.annotations.internal.TableGeneratorJpaAnnotation;
|
||||
import org.hibernate.boot.models.spi.GenericGeneratorRegistration;
|
||||
|
@ -19,28 +14,16 @@ import org.hibernate.boot.models.spi.SequenceGeneratorRegistration;
|
|||
import org.hibernate.boot.models.spi.TableGeneratorRegistration;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.*;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleGenericGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleSequenceGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleTableGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleUuidStrategy;
|
||||
import static org.hibernate.boot.model.internal.GeneratorParameters.identityTablesString;
|
||||
import static org.hibernate.boot.model.internal.GeneratorStrategies.mapLegacyNamedGenerator;
|
||||
import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME;
|
||||
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
|
||||
import static org.hibernate.id.IdentifierGenerator.JPA_ENTITY_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.IMPLICIT_NAME_BASE;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.PK;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.TABLE;
|
||||
import static org.hibernate.id.PersistentIdentifierGenerator.TABLES;
|
||||
|
||||
/**
|
||||
* SecondPass implementing delayed resolution of id-generators associated with an entity
|
||||
|
@ -57,46 +40,18 @@ import static org.hibernate.id.PersistentIdentifierGenerator.TABLES;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver {
|
||||
private final PersistentClass entityMapping;
|
||||
private final SimpleValue idValue;
|
||||
private final MemberDetails idMember;
|
||||
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
|
||||
public class StrictIdGeneratorResolverSecondPass extends AbstractEntityIdGeneratorResolver {
|
||||
public StrictIdGeneratorResolverSecondPass(
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
GeneratedValue generatedValue,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.entityMapping = entityMapping;
|
||||
this.idValue = idValue;
|
||||
this.idMember = idMember;
|
||||
this.buildingContext = buildingContext;
|
||||
super( entityMapping, idValue, idMember, generatedValue, buildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
final GeneratedValue generatedValue = idMember.getDirectAnnotationUsage( GeneratedValue.class );
|
||||
switch ( generatedValue.strategy() ) {
|
||||
case UUID -> handleUuidStrategy( idValue, idMember, buildingContext );
|
||||
case IDENTITY -> handleIdentityStrategy( idValue );
|
||||
case SEQUENCE -> handleSequenceStrategy( generatedValue );
|
||||
case TABLE -> handleTableStrategy( generatedValue );
|
||||
case AUTO -> handleAutoStrategy( generatedValue );
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSequenceStrategy(GeneratedValue generatedValue) {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedSequenceGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedSequenceGenerator( generatedValue );
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnnamedSequenceGenerator() {
|
||||
protected void handleUnnamedSequenceGenerator() {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
|
||||
// according to the spec, this should locate a generator with the same name as the entity-name
|
||||
|
@ -107,7 +62,6 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
handleSequenceGenerator(
|
||||
entityMapping.getJpaEntityName(),
|
||||
globalMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
|
@ -118,14 +72,14 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
handleSequenceGenerator(
|
||||
entityMapping.getJpaEntityName(),
|
||||
new SequenceGeneratorJpaAnnotation( metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private void handleNamedSequenceGenerator(GeneratedValue generatedValue) {
|
||||
@Override
|
||||
protected void handleNamedSequenceGenerator() {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
|
||||
final SequenceGeneratorRegistration globalMatch =
|
||||
|
@ -135,7 +89,6 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
handleSequenceGenerator(
|
||||
generatedValue.generator(),
|
||||
globalMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
|
@ -146,23 +99,14 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
handleSequenceGenerator(
|
||||
generatedValue.generator(),
|
||||
new SequenceGeneratorJpaAnnotation( generatedValue.generator(), metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private void handleTableStrategy(GeneratedValue generatedValue) {
|
||||
if ( generatedValue.generator().isEmpty() ) {
|
||||
handleUnnamedTableGenerator();
|
||||
}
|
||||
else {
|
||||
handleNamedTableGenerator( generatedValue );
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnnamedTableGenerator() {
|
||||
@Override
|
||||
protected void handleUnnamedTableGenerator() {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
|
||||
final TableGeneratorRegistration globalMatch =
|
||||
|
@ -174,6 +118,7 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
globalMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -184,11 +129,13 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
new TableGeneratorJpaAnnotation( metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private void handleNamedTableGenerator(GeneratedValue generatedValue) {
|
||||
@Override
|
||||
protected void handleNamedTableGenerator() {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
|
||||
final TableGeneratorRegistration globalMatch =
|
||||
|
@ -200,6 +147,7 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
globalMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
|
||||
|
@ -211,14 +159,22 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
new TableGeneratorJpaAnnotation( generatedValue.generator(), metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private void handleAutoStrategy(GeneratedValue generatedValue) {
|
||||
final String generator = generatedValue.generator();
|
||||
final String globalRegistrationName = generator.isEmpty() ? entityMapping.getJpaEntityName() : generator;
|
||||
@Override
|
||||
protected void handleUnnamedAutoGenerator() {
|
||||
handleAutoGenerator( entityMapping.getJpaEntityName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleNamedAutoGenerator() {
|
||||
handleAutoGenerator( generatedValue.generator() );
|
||||
}
|
||||
|
||||
private void handleAutoGenerator(String globalRegistrationName) {
|
||||
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
|
||||
final GlobalRegistrations globalRegistrations = metadataCollector.getGlobalRegistrations();
|
||||
|
||||
|
@ -228,7 +184,6 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
handleSequenceGenerator(
|
||||
globalRegistrationName,
|
||||
globalSequenceMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
|
@ -244,6 +199,7 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
globalTableMatch.configuration(),
|
||||
entityMapping,
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
return;
|
||||
|
@ -262,6 +218,10 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
return;
|
||||
}
|
||||
|
||||
if ( handleAsMetaAnnotated() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Implicit handling of UUID generation
|
||||
if ( idMember.getType().isImplementor( UUID.class )
|
||||
|| idMember.getType().isImplementor( String.class ) ) {
|
||||
|
@ -269,85 +229,16 @@ public class StrictIdGeneratorResolverSecondPass implements IdGeneratorResolver
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// Handle a few legacy Hibernate generators...
|
||||
if ( !generator.isEmpty() ) {
|
||||
final Class<? extends Generator> legacyNamedGenerator = mapLegacyNamedGenerator( generator, idValue );
|
||||
if ( legacyNamedGenerator != null ) {
|
||||
final Map<String,String> configuration = buildLegacyGeneratorConfig();
|
||||
//noinspection unchecked,rawtypes
|
||||
GeneratorBinder.createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( generator, legacyNamedGenerator.getName(), configuration ),
|
||||
idValue,
|
||||
(Map) configuration,
|
||||
buildingContext
|
||||
);
|
||||
if ( handleAsLegacyGenerator() ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
handleSequenceGenerator(
|
||||
globalRegistrationName,
|
||||
new SequenceGeneratorJpaAnnotation( generator, metadataCollector.getSourceModelBuildingContext() ),
|
||||
entityMapping,
|
||||
new SequenceGeneratorJpaAnnotation( generatedValue.generator(), metadataCollector.getSourceModelBuildingContext() ),
|
||||
idValue,
|
||||
idMember,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private HashMap<String, String> buildLegacyGeneratorConfig() {
|
||||
final Database database = buildingContext.getMetadataCollector().getDatabase();
|
||||
final Dialect dialect = database.getDialect();
|
||||
|
||||
final HashMap<String, String> configuration = new HashMap<>();
|
||||
|
||||
final String tableName = idValue.getTable().getQuotedName( dialect );
|
||||
configuration.put( TABLE, tableName );
|
||||
|
||||
final Column idColumn = (Column) idValue.getSelectables().get( 0);
|
||||
final String idColumnName = idColumn.getQuotedName( dialect );
|
||||
configuration.put( PK, idColumnName );
|
||||
|
||||
configuration.put( ENTITY_NAME, entityMapping.getEntityName() );
|
||||
configuration.put( JPA_ENTITY_NAME, entityMapping.getJpaEntityName() );
|
||||
|
||||
// The table name is not really a good default for subselect entities,
|
||||
// so use the JPA entity name which is short
|
||||
configuration.put(
|
||||
IMPLICIT_NAME_BASE,
|
||||
idValue.getTable().isSubselect()
|
||||
? entityMapping.getJpaEntityName()
|
||||
: idValue.getTable().getName()
|
||||
);
|
||||
|
||||
configuration.put( TABLES, identityTablesString( dialect, entityMapping.getRootClass() ) );
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public static void handleSequenceGenerator(
|
||||
String generatorName,
|
||||
SequenceGenerator generatorConfig,
|
||||
PersistentClass entityMapping,
|
||||
SimpleValue idValue,
|
||||
MemberDetails idMember,
|
||||
MetadataBuildingContext context) {
|
||||
//generator settings
|
||||
final Map<String, String> configuration = new HashMap<>();
|
||||
applyBaselineConfiguration( generatorConfig, idValue, entityMapping.getRootClass(), context, configuration::put );
|
||||
if ( generatorConfig == null ) {
|
||||
configuration.put( GENERATOR_NAME, generatorName );
|
||||
}
|
||||
else {
|
||||
SequenceStyleGenerator.applyConfiguration( generatorConfig, configuration::put );
|
||||
}
|
||||
|
||||
GeneratorBinder.createGeneratorFrom(
|
||||
new IdentifierGeneratorDefinition( generatorName, SequenceStyleGenerator.class.getName(), configuration ),
|
||||
idValue,
|
||||
context
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static java.lang.Integer.parseInt;
|
||||
|
@ -620,8 +621,8 @@ public class CockroachDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -196,6 +196,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
|
@ -2045,11 +2046,21 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
|
|||
* {@code "native"} is specified in {@code hbm.xml}.
|
||||
*
|
||||
* @return The name identifying the native generator strategy.
|
||||
*
|
||||
* @deprecated Use {@linkplain #getNativeValueGenerationStrategy()} instead
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return getNativeValueGenerationStrategy().name().toLowerCase( Locale.ROOT );
|
||||
}
|
||||
|
||||
/**
|
||||
* The native type of generation supported by this Dialect.
|
||||
*/
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return getIdentityColumnSupport().supportsIdentityColumns()
|
||||
? "identity"
|
||||
: "sequence";
|
||||
? GenerationType.IDENTITY
|
||||
: GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -87,6 +87,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
|
@ -349,8 +350,8 @@ public class DialectDelegateWrapper extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return wrapped.getNativeIdentifierGeneratorStrategy();
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return wrapped.getNativeValueGenerationStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,6 +100,7 @@ import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeI
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
@ -1045,8 +1046,8 @@ public class OracleDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
// features which change between 8i, 9i, and 10g ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -95,6 +95,7 @@ import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
@ -856,8 +857,8 @@ public class PostgreSQLDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getNativeIdentifierGeneratorStrategy() {
|
||||
return "sequence";
|
||||
public GenerationType getNativeValueGenerationStrategy() {
|
||||
return GenerationType.SEQUENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.id;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.boot.model.internal.GeneratorParameters;
|
||||
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.models.annotations.internal.UuidGeneratorAnnotation;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.AnnotationBasedGenerator;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.GeneratorCreationContext;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.enhanced.TableGenerator;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.id.uuid.UuidGenerator;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
|
||||
import static org.hibernate.id.IdentifierGenerator.GENERATOR_NAME;
|
||||
import static org.hibernate.id.OptimizableGenerator.INCREMENT_PARAM;
|
||||
|
||||
/**
|
||||
* Generator that picks a strategy based on the {@linkplain Dialect#getNativeValueGenerationStrategy() dialect}.
|
||||
*
|
||||
* @see org.hibernate.annotations.NativeGenerator
|
||||
* @since 7.0
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NativeGenerator
|
||||
implements OnExecutionGenerator, BeforeExecutionGenerator, Configurable, ExportableProducer, AnnotationBasedGenerator<org.hibernate.annotations.NativeGenerator> {
|
||||
private GenerationType generationType;
|
||||
private org.hibernate.annotations.NativeGenerator annotation;
|
||||
private Generator dialectNativeGenerator;
|
||||
|
||||
public GenerationType getGenerationType() {
|
||||
return generationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return dialectNativeGenerator.getEventTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution() {
|
||||
return dialectNativeGenerator.generatedOnExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(
|
||||
org.hibernate.annotations.NativeGenerator annotation,
|
||||
Member member,
|
||||
GeneratorCreationContext context) {
|
||||
this.annotation = annotation;
|
||||
|
||||
generationType = context.getDatabase()
|
||||
.getDialect()
|
||||
.getNativeValueGenerationStrategy();
|
||||
switch ( generationType ) {
|
||||
case TABLE: {
|
||||
dialectNativeGenerator = new TableGenerator();
|
||||
break;
|
||||
}
|
||||
case IDENTITY: {
|
||||
dialectNativeGenerator = new IdentityGenerator();
|
||||
context.getProperty().getValue().getColumns().get( 0 ).setIdentity( true );
|
||||
break;
|
||||
}
|
||||
case UUID: {
|
||||
dialectNativeGenerator = new UuidGenerator( new UuidGeneratorAnnotation( null ), member );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert generationType == GenerationType.AUTO || generationType == GenerationType.SEQUENCE;
|
||||
dialectNativeGenerator = new SequenceStyleGenerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(GeneratorCreationContext creationContext, Properties parameters) {
|
||||
if ( dialectNativeGenerator instanceof SequenceStyleGenerator sequenceStyleGenerator ) {
|
||||
applyProperties( parameters, annotation.sequenceForm(), creationContext );
|
||||
sequenceStyleGenerator.configure( creationContext, parameters );
|
||||
}
|
||||
else if ( dialectNativeGenerator instanceof TableGenerator tableGenerator ) {
|
||||
applyProperties( parameters, annotation.tableForm(), creationContext );
|
||||
tableGenerator.configure( creationContext, parameters );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerExportables(Database database) {
|
||||
if ( dialectNativeGenerator instanceof ExportableProducer exportableProducer ) {
|
||||
exportableProducer.registerExportables(database);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(SqlStringGenerationContext context) {
|
||||
if ( dialectNativeGenerator instanceof Configurable configurable ) {
|
||||
configurable.initialize(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return ((BeforeExecutionGenerator) dialectNativeGenerator).generate(session, owner, currentValue, eventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||
return ((OnExecutionGenerator) dialectNativeGenerator).referenceColumnsInSql(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePropertyValue() {
|
||||
return ((OnExecutionGenerator) dialectNativeGenerator).writePropertyValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||
return ((OnExecutionGenerator) dialectNativeGenerator).getReferencedColumnValues(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate(EntityPersister persister) {
|
||||
return ((OnExecutionGenerator) dialectNativeGenerator).getGeneratedIdentifierDelegate(persister);
|
||||
}
|
||||
|
||||
private void applyProperties(
|
||||
Properties properties,
|
||||
SequenceGenerator sequenceAnnotation,
|
||||
GeneratorCreationContext creationContext) {
|
||||
//noinspection unchecked,rawtypes
|
||||
final Map<String,Object> mapRef = (Map) properties;
|
||||
mapRef.put( GENERATOR_NAME, sequenceAnnotation.name() );
|
||||
applyCommonConfiguration( mapRef, creationContext );
|
||||
SequenceStyleGenerator.applyConfiguration( sequenceAnnotation, mapRef::put );
|
||||
}
|
||||
|
||||
private void applyProperties(
|
||||
Properties properties,
|
||||
jakarta.persistence.TableGenerator tableGenerator,
|
||||
GeneratorCreationContext creationContext) {
|
||||
//noinspection unchecked,rawtypes
|
||||
final Map<String,Object> mapRef = (Map) properties;
|
||||
mapRef.put( GENERATOR_NAME, tableGenerator.name() );
|
||||
applyCommonConfiguration( mapRef, creationContext );
|
||||
TableGenerator.applyConfiguration( tableGenerator, mapRef::put );
|
||||
}
|
||||
|
||||
private static void applyCommonConfiguration(
|
||||
Map<String, Object> mapRef,
|
||||
GeneratorCreationContext context) {
|
||||
GeneratorParameters.collectParameters(
|
||||
(SimpleValue) context.getProperty().getValue(),
|
||||
context.getDatabase().getDialect(),
|
||||
context.getRootClass(),
|
||||
mapRef::put
|
||||
);
|
||||
mapRef.put( INCREMENT_PARAM, 1 );
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
|||
import org.hibernate.id.enhanced.StandardNamingStrategy;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import org.hibernate.testing.orm.junit.BaseUnitTest;
|
||||
|
@ -129,7 +130,7 @@ public class SequenceNamingStrategyTest {
|
|||
assertThat( sequence ).isNotNull();
|
||||
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityType.getName() );
|
||||
final IdentifierGenerator generator = extractGenerator( entityBinding );
|
||||
final IdentifierGenerator generator = extractGenerator( metadata, entityBinding );
|
||||
assertThat( generator ).isInstanceOf( SequenceStyleGenerator.class );
|
||||
final SequenceStyleGenerator sequenceStyleGenerator = (SequenceStyleGenerator) generator;
|
||||
assertThat( sequenceStyleGenerator.getDatabaseStructure() ).isInstanceOf( SequenceStructure.class );
|
||||
|
@ -158,9 +159,14 @@ public class SequenceNamingStrategyTest {
|
|||
}
|
||||
}
|
||||
|
||||
private IdentifierGenerator extractGenerator(PersistentClass entityBinding) {
|
||||
private IdentifierGenerator extractGenerator(MetadataImplementor metadataImplementor, PersistentClass entityBinding) {
|
||||
KeyValue keyValue = entityBinding.getIdentifier();
|
||||
final Generator generator = keyValue.createGenerator(null, null);
|
||||
final Generator generator = keyValue.createGenerator(
|
||||
metadataImplementor.getDatabase().getDialect(),
|
||||
entityBinding.getRootClass(),
|
||||
entityBinding.getIdentifierProperty(),
|
||||
new GeneratorSettingsImpl( metadataImplementor )
|
||||
);
|
||||
return generator instanceof IdentifierGenerator ? (IdentifierGenerator) generator : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.id.enhanced.StandardNamingStrategy;
|
|||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import org.hibernate.testing.orm.junit.BaseUnitTest;
|
||||
|
@ -112,7 +113,7 @@ public class TableNamingStrategyTest {
|
|||
assertThat( table ).isNotNull();
|
||||
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityType.getName() );
|
||||
final IdentifierGenerator generator = extractGenerator( entityBinding );
|
||||
final IdentifierGenerator generator = extractGenerator( entityBinding, metadata );
|
||||
assertThat( generator ).isInstanceOf( org.hibernate.id.enhanced.TableGenerator.class );
|
||||
final org.hibernate.id.enhanced.TableGenerator tableGenerator = (org.hibernate.id.enhanced.TableGenerator) generator;
|
||||
assertThat( tableGenerator.getTableName() ).isEqualTo( expectedName );
|
||||
|
@ -139,9 +140,14 @@ public class TableNamingStrategyTest {
|
|||
}
|
||||
}
|
||||
|
||||
private IdentifierGenerator extractGenerator(PersistentClass entityBinding) {
|
||||
private IdentifierGenerator extractGenerator(PersistentClass entityBinding, MetadataImplementor metadata) {
|
||||
KeyValue keyValue = entityBinding.getIdentifier();
|
||||
final Generator generator = keyValue.createGenerator(null, null);
|
||||
final Generator generator = keyValue.createGenerator(
|
||||
metadata.getDatabase().getDialect(),
|
||||
entityBinding.getRootClass(),
|
||||
entityBinding.getIdentifierProperty(),
|
||||
new GeneratorSettingsImpl( metadata )
|
||||
);
|
||||
return generator instanceof IdentifierGenerator ? (IdentifierGenerator) generator : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.mapping.IdentifierBag;
|
|||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
|
||||
import org.hibernate.testing.orm.junit.FailureExpectedExtension;
|
||||
import org.hibernate.testing.util.ServiceRegistryUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -85,7 +87,12 @@ public class AutoGenerationTypeTests {
|
|||
final PersistentClass entityBinding = metadata.getEntityBinding( Entity2.class.getName() );
|
||||
final KeyValue idMapping = entityBinding.getRootClass().getIdentifier();
|
||||
Dialect dialect = new H2Dialect();
|
||||
final Generator generator = idMapping.createGenerator( dialect, entityBinding.getRootClass());
|
||||
final Generator generator = idMapping.createGenerator(
|
||||
dialect,
|
||||
entityBinding.getRootClass(),
|
||||
entityBinding.getIdentifierProperty(),
|
||||
new GeneratorSettingsImpl( metadata )
|
||||
);
|
||||
final SequenceStyleGenerator idGenerator = (SequenceStyleGenerator) (generator instanceof IdentifierGenerator ? (IdentifierGenerator) generator : null);
|
||||
|
||||
final DatabaseStructure database2Structure = idGenerator.getDatabaseStructure();
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.n_ative;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.mapping.GeneratorSettings;
|
||||
|
||||
import static org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl.fromExplicit;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GeneratorSettingsImpl implements GeneratorSettings {
|
||||
private final String defaultCatalog;
|
||||
private final String defaultSchema;
|
||||
private final SqlStringGenerationContext sqlStringGenerationContext;
|
||||
|
||||
public GeneratorSettingsImpl(Metadata domainModel) {
|
||||
final Database database = domainModel.getDatabase();
|
||||
final Namespace defaultNamespace = database.getDefaultNamespace();
|
||||
final Namespace.Name defaultNamespaceName = defaultNamespace.getName();
|
||||
|
||||
defaultCatalog = defaultNamespaceName.getCatalog() == null
|
||||
? ""
|
||||
: defaultNamespaceName.getCatalog().render( database.getDialect() );
|
||||
defaultSchema = defaultNamespaceName.getSchema() == null
|
||||
? ""
|
||||
: defaultNamespaceName.getSchema().render( database.getDialect() );
|
||||
|
||||
sqlStringGenerationContext = fromExplicit(
|
||||
database.getJdbcEnvironment(),
|
||||
database,
|
||||
defaultCatalog,
|
||||
defaultSchema
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultCatalog() {
|
||||
return defaultCatalog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultSchema() {
|
||||
return defaultSchema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlStringGenerationContext getSqlStringGenerationContext() {
|
||||
return sqlStringGenerationContext;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.n_ative.local;
|
||||
|
||||
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.NativeGenerator;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = NativeGeneratorClassTest.NativeEntity.class)
|
||||
public class NativeGeneratorClassTest {
|
||||
@Test void test(DomainModelScope domainModelScope, SessionFactoryScope scope) {
|
||||
scope.inTransaction(s -> s.persist(new NativeEntity()));
|
||||
|
||||
final PersistentClass entityBinding = domainModelScope.getEntityBinding( NativeEntity.class );
|
||||
final Property idProperty = entityBinding.getIdentifierProperty();
|
||||
final KeyValue identifier = entityBinding.getIdentifier();
|
||||
|
||||
final Generator generator = identifier.createGenerator(
|
||||
domainModelScope.getDomainModel().getDatabase().getDialect(),
|
||||
entityBinding.getRootClass(),
|
||||
idProperty,
|
||||
new GeneratorSettingsImpl( domainModelScope.getDomainModel() )
|
||||
);
|
||||
assertThat( generator ).isInstanceOf( NativeGenerator.class );
|
||||
}
|
||||
|
||||
@Entity
|
||||
@org.hibernate.annotations.NativeGenerator
|
||||
public static class NativeEntity {
|
||||
@Id @GeneratedValue
|
||||
long id;
|
||||
String data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.n_ative.local;
|
||||
|
||||
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.NativeGenerator;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = NativeGeneratorMemberTest.NativeEntity.class)
|
||||
public class NativeGeneratorMemberTest {
|
||||
@Test void test(DomainModelScope domainModelScope, SessionFactoryScope scope) {
|
||||
scope.inTransaction(s -> s.persist(new NativeEntity()));
|
||||
|
||||
final PersistentClass entityBinding = domainModelScope.getEntityBinding( NativeEntity.class );
|
||||
final Property idProperty = entityBinding.getIdentifierProperty();
|
||||
final KeyValue identifier = entityBinding.getIdentifier();
|
||||
|
||||
final Generator generator = identifier.createGenerator(
|
||||
domainModelScope.getDomainModel().getDatabase().getDialect(),
|
||||
entityBinding.getRootClass(),
|
||||
idProperty,
|
||||
new GeneratorSettingsImpl( domainModelScope.getDomainModel() )
|
||||
);
|
||||
assertThat( generator ).isInstanceOf( NativeGenerator.class );
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class NativeEntity {
|
||||
@Id @GeneratedValue
|
||||
@org.hibernate.annotations.NativeGenerator
|
||||
long id;
|
||||
String data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.n_ative.pkg;
|
||||
|
||||
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.NativeGenerator;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.orm.test.idgen.n_ative.GeneratorSettingsImpl;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = NativeGeneratorPackageTest.NativeEntity.class)
|
||||
public class NativeGeneratorPackageTest {
|
||||
@Test void test(DomainModelScope domainModelScope, SessionFactoryScope scope) {
|
||||
scope.inTransaction(s -> s.persist(new NativeEntity()));
|
||||
|
||||
final PersistentClass entityBinding = domainModelScope.getEntityBinding( NativeEntity.class );
|
||||
final Property idProperty = entityBinding.getIdentifierProperty();
|
||||
final KeyValue identifier = entityBinding.getIdentifier();
|
||||
final Generator generator = identifier.createGenerator(
|
||||
domainModelScope.getDomainModel().getDatabase().getDialect(),
|
||||
entityBinding.getRootClass(),
|
||||
idProperty,
|
||||
new GeneratorSettingsImpl( domainModelScope.getDomainModel() )
|
||||
);
|
||||
assertThat( generator ).isInstanceOf( NativeGenerator.class );
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class NativeEntity {
|
||||
@Id @GeneratedValue
|
||||
long id;
|
||||
String data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@org.hibernate.annotations.NativeGenerator
|
||||
package org.hibernate.orm.test.idgen.n_ative.pkg;
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.userdefined;
|
||||
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.GeneratorCreationContext;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
|
||||
public class NativeGenerator
|
||||
implements OnExecutionGenerator, BeforeExecutionGenerator, Configurable, ExportableProducer {
|
||||
|
||||
private final Generator generator;
|
||||
|
||||
public NativeGenerator(NativeId nativeId, Member member, GeneratorCreationContext creationContext) {
|
||||
final String strategy = creationContext.getDatabase().getDialect().getNativeIdentifierGeneratorStrategy();
|
||||
switch (strategy) {
|
||||
case "sequence":
|
||||
generator = new SequenceStyleGenerator();
|
||||
break;
|
||||
case "identity":
|
||||
creationContext.getProperty().getValue().getColumns().get(0).setIdentity(true);
|
||||
generator = new IdentityGenerator();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return generator.getEventTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution() {
|
||||
return generator.generatedOnExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(GeneratorCreationContext creationContext, Properties parameters) {
|
||||
if ( generator instanceof Configurable ) {
|
||||
((Configurable) generator).configure( creationContext, parameters );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerExportables(Database database) {
|
||||
if ( generator instanceof ExportableProducer exportableProducer ) {
|
||||
exportableProducer.registerExportables(database);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(SqlStringGenerationContext context) {
|
||||
if ( generator instanceof Configurable configurable ) {
|
||||
configurable.initialize(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return ((BeforeExecutionGenerator) generator).generate(session, owner, currentValue, eventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||
return ((OnExecutionGenerator) generator).referenceColumnsInSql(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePropertyValue() {
|
||||
return ((OnExecutionGenerator) generator).writePropertyValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||
return ((OnExecutionGenerator) generator).getReferencedColumnValues(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate(EntityPersister persister) {
|
||||
return ((OnExecutionGenerator) generator).getGeneratedIdentifierDelegate(persister);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.userdefined;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = NativeGeneratorTest.NativeEntity.class)
|
||||
public class NativeGeneratorTest {
|
||||
@Test void test(SessionFactoryScope scope) {
|
||||
scope.inTransaction(s -> s.persist(new NativeEntity()));
|
||||
}
|
||||
@Entity
|
||||
public static class NativeEntity {
|
||||
@Id @NativeId
|
||||
long id;
|
||||
String data;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.idgen.userdefined;
|
||||
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@IdGeneratorType(NativeGenerator.class)
|
||||
public @interface NativeId {
|
||||
}
|
Loading…
Reference in New Issue