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
This commit is contained in:
parent
c394261508
commit
ce4f22f400
|
@ -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<? extends IdentifierGenerator> value();
|
||||
}
|
|
@ -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<? extends IdentifierGenerator> 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<String, IdentifierGeneratorDefinition> localGenerators = (HashMap<String, IdentifierGeneratorDefinition>) 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<String, IdentifierGeneratorDefinition> localGenerators = (HashMap<String, IdentifierGeneratorDefinition>) 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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 extends Annotation> T findAnnotation(XAnnotatedElement xAnnotatedElement, Class<T> annotationType) {
|
||||
public static <T extends Annotation> T findAnnotation(XAnnotatedElement xAnnotatedElement, Class<T> 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 extends Annotation, T extends Annotation> A findContainingAnnotation(
|
||||
XAnnotatedElement xAnnotatedElement,
|
||||
Class<T> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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" ) );
|
||||
} );
|
||||
}
|
||||
}
|
|
@ -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<? extends Optimizer> optimizerStrategy() default Optimizer.class;
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue