From ce4f22f4003d53e6a8dfdfa2b95b1a1f6b204679 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 7 Dec 2021 19:21:05 -0600 Subject: [PATCH] HHH-14497 - Drop legacy id-generator settings; HHH-14718 - Drop deprecated generator implementations; HHH-14959 - Drop IdentifierGeneratorFactory as a Service; HHH-14960 - Add @GeneratorType for better custom generator config --- .../annotations/IdGeneratorType.java | 27 +++++ .../org/hibernate/cfg/AnnotationBinder.java | 107 ++++++++++++------ .../cfg/annotations/HCANNHelper.java | 29 ++++- .../spi/CustomIdGeneratorCreationContext.java | 25 ++++ .../mapping/IdentifierGeneratorCreator.java | 15 +++ .../org/hibernate/mapping/SimpleValue.java | 84 +++++++++++--- .../test/id/custom/CustomGeneratorTests.java | 42 +++++++ .../orm/test/id/custom/Sequence.java | 27 +++++ .../id/custom/SimpleSequenceGenerator.java | 84 ++++++++++++++ .../orm/test/id/custom/TheEntity.java | 42 +++++++ 10 files changed, 427 insertions(+), 55 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/IdGeneratorType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/id/factory/spi/CustomIdGeneratorCreationContext.java create mode 100644 hibernate-core/src/main/java/org/hibernate/mapping/IdentifierGeneratorCreator.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/CustomGeneratorTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/Sequence.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/SimpleSequenceGenerator.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/TheEntity.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/IdGeneratorType.java b/hibernate-core/src/main/java/org/hibernate/annotations/IdGeneratorType.java new file mode 100644 index 0000000000..4543be03cc --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/IdGeneratorType.java @@ -0,0 +1,27 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.hibernate.id.IdentifierGenerator; + +/** + * Meta-annotation used to mark another annotation as providing configuration + * for a custom {@link org.hibernate.id.IdentifierGenerator}. + */ +@Target( value = ElementType.ANNOTATION_TYPE ) +@Retention( RetentionPolicy.RUNTIME ) +public @interface IdGeneratorType { + /** + * The IdentifierGenerator being configured + */ + Class value(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 4c4b38539f..c62f501df0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -6,6 +6,8 @@ */ package org.hibernate.cfg; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -22,6 +24,7 @@ import java.util.Set; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; +import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; @@ -46,6 +49,7 @@ import org.hibernate.annotations.ForeignKey; import org.hibernate.annotations.Formula; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerators; +import org.hibernate.annotations.IdGeneratorType; import org.hibernate.annotations.Index; import org.hibernate.annotations.JavaTypeRegistration; import org.hibernate.annotations.JavaTypeRegistrations; @@ -100,6 +104,8 @@ import org.hibernate.cfg.annotations.TableBinder; import org.hibernate.cfg.internal.NullableDiscriminatorColumnSecondPass; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.jpa.event.internal.CallbackDefinitionResolverLegacyImpl; @@ -2544,46 +2550,75 @@ public final class AnnotationBinder { final boolean isComponent = entityXClass.isAnnotationPresent( Embeddable.class ) || idXProperty.isAnnotationPresent( EmbeddedId.class ); - GeneratedValue generatedValue = idXProperty.getAnnotation( GeneratedValue.class ); - String generatorType = generatedValue != null - ? generatorType( generatedValue, buildingContext, entityXClass ) - : "assigned"; - String generatorName = generatedValue != null - ? generatedValue.generator() - : BinderHelper.ANNOTATION_STRING_DEFAULT; - if ( isComponent ) { - //a component must not have any generator - generatorType = "assigned"; - } + final Annotation generatorAnnotation = HCANNHelper.findContainingAnnotation( idXProperty, IdGeneratorType.class, buildingContext ); + if ( generatorAnnotation != null ) { + final IdGeneratorType idGeneratorType = generatorAnnotation.annotationType().getAnnotation( IdGeneratorType.class ); + assert idGeneratorType != null; - if ( isGlobalGeneratorNameGlobal( buildingContext ) ) { - buildGenerators( idXProperty, buildingContext ); - SecondPass secondPass = new IdGeneratorResolverSecondPass( - idValue, - idXProperty, - generatorType, - generatorName, - buildingContext - ); - buildingContext.getMetadataCollector().addSecondPass( secondPass ); + idValue.setCustomIdGeneratorCreator( (context) -> { + final Class generatorClass = idGeneratorType.value(); + try { + return generatorClass + .getConstructor( generatorAnnotation.annotationType(), CustomIdGeneratorCreationContext.class ) + .newInstance( generatorAnnotation, context ); + } + catch (NoSuchMethodException e) { + throw new HibernateException( + "Unable to find appropriate constructor for @IdGeneratorType handling : " + generatorClass.getName(), + e + ); + } + catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new HibernateException( + "Unable to invoke constructor for @IdGeneratorType handling : " + generatorClass.getName(), + e + ); + } + } ); } else { - //clone classGenerator and override with local values - HashMap localGenerators = (HashMap) classGenerators - .clone(); - localGenerators.putAll( buildGenerators( idXProperty, buildingContext ) ); - BinderHelper.makeIdGenerator( - idValue, - idXProperty, - generatorType, - generatorName, - buildingContext, - localGenerators - ); - } + GeneratedValue generatedValue = idXProperty.getAnnotation( GeneratedValue.class ); - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "Bind {0} on {1}", ( isComponent ? "@EmbeddedId" : "@Id" ), inferredData.getPropertyName() ); + String generatorType = generatedValue != null + ? generatorType( generatedValue, buildingContext, entityXClass ) + : "assigned"; + String generatorName = generatedValue != null + ? generatedValue.generator() + : BinderHelper.ANNOTATION_STRING_DEFAULT; + if ( isComponent ) { + //a component must not have any generator + generatorType = "assigned"; + } + + if ( isGlobalGeneratorNameGlobal( buildingContext ) ) { + buildGenerators( idXProperty, buildingContext ); + SecondPass secondPass = new IdGeneratorResolverSecondPass( + idValue, + idXProperty, + generatorType, + generatorName, + buildingContext + ); + buildingContext.getMetadataCollector().addSecondPass( secondPass ); + } + else { + //clone classGenerator and override with local values + HashMap localGenerators = (HashMap) classGenerators + .clone(); + localGenerators.putAll( buildGenerators( idXProperty, buildingContext ) ); + BinderHelper.makeIdGenerator( + idValue, + idXProperty, + generatorType, + generatorName, + buildingContext, + localGenerators + ); + } + + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Bind {0} on {1}", ( isComponent ? "@EmbeddedId" : "@Id" ), inferredData.getPropertyName() ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/HCANNHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/HCANNHelper.java index 322e4cbb4d..0372dbe4f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/HCANNHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/HCANNHelper.java @@ -13,6 +13,7 @@ import org.hibernate.Internal; import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.java.JavaXMember; +import org.hibernate.boot.spi.MetadataBuildingContext; /** * Manage the various fun-ness of dealing with HCANN... @@ -57,7 +58,7 @@ public final class HCANNHelper { * * @implNote Searches only one level deep */ - static T findAnnotation(XAnnotatedElement xAnnotatedElement, Class annotationType) { + public static T findAnnotation(XAnnotatedElement xAnnotatedElement, Class annotationType) { // first, see if we can find it directly... final T direct = xAnnotatedElement.getAnnotation( annotationType ); if ( direct != null ) { @@ -82,4 +83,30 @@ public final class HCANNHelper { return null; } + + /** + * Locate the annotation, relative to `xAnnotatedElement`, which contains + * the passed type of annotation. + * + * @implNote Searches only one level deep + */ + public static A findContainingAnnotation( + XAnnotatedElement xAnnotatedElement, + Class annotationType, + MetadataBuildingContext context) { + // xAnnotatedElement = id-prop + + for ( int i = 0; i < xAnnotatedElement.getAnnotations().length; i++ ) { + final Annotation annotation = xAnnotatedElement.getAnnotations()[ i ]; + // annotation = @Sequence + + final T metaAnn = annotation.annotationType().getAnnotation( annotationType ); + if ( metaAnn != null ) { + //noinspection unchecked + return (A) annotation; + } + } + + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/factory/spi/CustomIdGeneratorCreationContext.java b/hibernate-core/src/main/java/org/hibernate/id/factory/spi/CustomIdGeneratorCreationContext.java new file mode 100644 index 0000000000..66a462af10 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/id/factory/spi/CustomIdGeneratorCreationContext.java @@ -0,0 +1,25 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.id.factory.spi; + +import org.hibernate.Incubating; +import org.hibernate.boot.model.relational.Database; +import org.hibernate.id.factory.IdentifierGeneratorFactory; +import org.hibernate.mapping.RootClass; +import org.hibernate.service.ServiceRegistry; + +@Incubating +public interface CustomIdGeneratorCreationContext { + IdentifierGeneratorFactory getIdentifierGeneratorFactory(); + Database getDatabase(); + ServiceRegistry getServiceRegistry(); + + String getDefaultCatalog(); + String getDefaultSchema(); + + RootClass getRootClass(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierGeneratorCreator.java b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierGeneratorCreator.java new file mode 100644 index 0000000000..466c85db9e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierGeneratorCreator.java @@ -0,0 +1,15 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.mapping; + +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; + +@FunctionalInterface +public interface IdentifierGeneratorCreator { + IdentifierGenerator createGenerator(CustomIdGeneratorCreationContext context); +} diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index c3976227d3..7a395a0698 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -16,7 +16,6 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; -import jakarta.persistence.AttributeConverter; import org.hibernate.FetchMode; import org.hibernate.MappingException; @@ -25,6 +24,7 @@ import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext; +import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.InFlightMetadataCollector; @@ -33,13 +33,13 @@ import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.spi.Mapping; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.OptimizableGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; +import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; @@ -59,6 +59,8 @@ import org.hibernate.type.descriptor.jdbc.NationalizedTypeMappings; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.DynamicParameterizedType; +import jakarta.persistence.AttributeConverter; + /** * Any value that maps to columns. * @author Gavin King @@ -84,6 +86,7 @@ public abstract class SimpleValue implements KeyValue { private Properties identifierGeneratorProperties; private String identifierGeneratorStrategy = DEFAULT_ID_GEN_STRATEGY; private String nullValue; + private Table table; private String foreignKeyName; private String foreignKeyDefinition; @@ -288,6 +291,7 @@ public abstract class SimpleValue implements KeyValue { } } + private IdentifierGeneratorCreator customIdGeneratorCreator; private IdentifierGenerator identifierGenerator; /** @@ -301,6 +305,14 @@ public abstract class SimpleValue implements KeyValue { return identifierGenerator; } + public void setCustomIdGeneratorCreator(IdentifierGeneratorCreator customIdGeneratorCreator) { + this.customIdGeneratorCreator = customIdGeneratorCreator; + } + + public IdentifierGeneratorCreator getCustomIdGeneratorCreator() { + return customIdGeneratorCreator; + } + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory identifierGeneratorFactory, @@ -316,11 +328,47 @@ public abstract class SimpleValue implements KeyValue { String defaultCatalog, String defaultSchema, RootClass rootClass) throws MappingException { - if ( identifierGenerator != null ) { return identifierGenerator; } + if ( customIdGeneratorCreator != null ) { + final CustomIdGeneratorCreationContext creationContext = new CustomIdGeneratorCreationContext() { + @Override + public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { + return identifierGeneratorFactory; + } + + @Override + public Database getDatabase() { + return buildingContext.getMetadataCollector().getDatabase(); + } + + @Override + public ServiceRegistry getServiceRegistry() { + return buildingContext.getBootstrapContext().getServiceRegistry(); + } + + @Override + public String getDefaultCatalog() { + return defaultCatalog; + } + + @Override + public String getDefaultSchema() { + return defaultSchema; + } + + @Override + public RootClass getRootClass() { + return rootClass; + } + }; + + identifierGenerator = customIdGeneratorCreator.createGenerator( creationContext ); + return identifierGenerator; + } + final Properties params = new Properties(); // This is for backwards compatibility only; @@ -407,14 +455,6 @@ public abstract class SimpleValue implements KeyValue { return FetchMode.SELECT; } - public Properties getIdentifierGeneratorProperties() { - return identifierGeneratorProperties; - } - - public String getNullValue() { - return nullValue; - } - public Table getTable() { return table; } @@ -426,11 +466,23 @@ public abstract class SimpleValue implements KeyValue { public String getIdentifierGeneratorStrategy() { return identifierGeneratorStrategy; } - + + /** + * Sets the identifierGeneratorStrategy. + * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set + */ + public void setIdentifierGeneratorStrategy(String identifierGeneratorStrategy) { + this.identifierGeneratorStrategy = identifierGeneratorStrategy; + } + public boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect) { return IdentityGenerator.class.isAssignableFrom(identifierGeneratorFactory.getIdentifierGeneratorClass( identifierGeneratorStrategy )); } + public Properties getIdentifierGeneratorProperties() { + return identifierGeneratorProperties; + } + /** * Sets the identifierGeneratorProperties. * @param identifierGeneratorProperties The identifierGeneratorProperties to set @@ -451,12 +503,8 @@ public abstract class SimpleValue implements KeyValue { } } - /** - * Sets the identifierGeneratorStrategy. - * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set - */ - public void setIdentifierGeneratorStrategy(String identifierGeneratorStrategy) { - this.identifierGeneratorStrategy = identifierGeneratorStrategy; + public String getNullValue() { + return nullValue; } /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/CustomGeneratorTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/CustomGeneratorTests.java new file mode 100644 index 0000000000..879122fc34 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/CustomGeneratorTests.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.id.custom; + +import org.hibernate.mapping.BasicValue; +import org.hibernate.mapping.Property; + +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 static org.assertj.core.api.Assertions.assertThat; + +@DomainModel( annotatedClasses = TheEntity.class ) +@SessionFactory +public class CustomGeneratorTests { + @Test + public void verifyModel(DomainModelScope scope) { + scope.withHierarchy( TheEntity.class, (descriptor) -> { + final Property idProperty = descriptor.getIdentifierProperty(); + final BasicValue value = (BasicValue) idProperty.getValue(); + + assertThat( value.getCustomIdGeneratorCreator() ).isNotNull(); + + final String strategy = value.getIdentifierGeneratorStrategy(); + assertThat( strategy ).isEqualTo( "assigned" ); + } ); + } + + @Test + public void basicUseTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + session.persist( new TheEntity( "steve" ) ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/Sequence.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/Sequence.java new file mode 100644 index 0000000000..8164c7fa44 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/Sequence.java @@ -0,0 +1,27 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.id.custom; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.hibernate.annotations.IdGeneratorType; +import org.hibernate.id.enhanced.Optimizer; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@IdGeneratorType( SimpleSequenceGenerator.class ) +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Sequence { + String name(); + int startWith() default 1; + int incrementBy() default 50; + Class optimizerStrategy() default Optimizer.class; +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/SimpleSequenceGenerator.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/SimpleSequenceGenerator.java new file mode 100644 index 0000000000..3771d5534f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/SimpleSequenceGenerator.java @@ -0,0 +1,84 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.id.custom; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.Database; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; + +public class SimpleSequenceGenerator implements IdentifierGenerator { + private final Identifier sequenceName; + private final String sqlSelectFrag; + + public SimpleSequenceGenerator(Sequence config, CustomIdGeneratorCreationContext context) { + final String name = config.name(); + + // ignore the other config for now... + + final Database database = context.getDatabase(); + final IdentifierHelper identifierHelper = database.getJdbcEnvironment().getIdentifierHelper(); + + final org.hibernate.boot.model.relational.Sequence sequence = database.getDefaultNamespace().createSequence( + identifierHelper.toIdentifier( name ), + (physicalName) -> new org.hibernate.boot.model.relational.Sequence( + null, + database.getDefaultNamespace().getPhysicalName().getCatalog(), + database.getDefaultNamespace().getPhysicalName().getSchema(), + physicalName, + 1, + 50 + ) + ); + this.sequenceName = sequence.getName().getSequenceName(); + + this.sqlSelectFrag = database + .getDialect() + .getSequenceSupport() + .getSequenceNextValString( sequenceName.render( database.getDialect() ) ); + } + + @Override + public Object generate(SharedSessionContractImplementor session, Object object) { + try { + final PreparedStatement st = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sqlSelectFrag ); + try { + final ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st ); + try { + rs.next(); + return rs.getInt( 1 ); + } + finally { + try { + session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( rs, st ); + } + catch( Throwable ignore ) { + // intentionally empty + } + } + } + finally { + session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st ); + session.getJdbcCoordinator().afterStatementExecution(); + } + + } + catch ( SQLException sqle) { + throw session.getJdbcServices().getSqlExceptionHelper().convert( + sqle, + "could not get next sequence value", + sqlSelectFrag + ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/TheEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/TheEntity.java new file mode 100644 index 0000000000..8471494ad7 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/custom/TheEntity.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.id.custom; + +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import jakarta.persistence.Id; +import jakarta.persistence.Basic; + +@Entity(name = "TheEntity") +@Table(name = "TheEntity") +public class TheEntity { + @Id + @Sequence( name = "seq1" ) + public Integer id; + @Basic + public String name; + + private TheEntity() { + // for Hibernate use + } + + public TheEntity(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file