HHH-18136 make it easier to write Generators which delegate to "old" id generation infrastructure
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
030b7946d4
commit
e721180435
|
@ -9,6 +9,8 @@ package org.hibernate.id;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.boot.model.relational.Database;
|
||||||
|
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -21,12 +23,30 @@ import org.hibernate.type.Type;
|
||||||
public interface Configurable {
|
public interface Configurable {
|
||||||
/**
|
/**
|
||||||
* Configure this instance, given the value of parameters
|
* Configure this instance, given the value of parameters
|
||||||
* specified by the user as {@code <param>} elements.
|
* specified by the user as XML {@code <param>} elements and
|
||||||
|
* {@link org.hibernate.annotations.Parameter @Parameter}
|
||||||
|
* annotations.
|
||||||
|
* <p>
|
||||||
* This method is called just once, following instantiation.
|
* This method is called just once, following instantiation.
|
||||||
|
* If this instance also implements {@code ExportableProducer},
|
||||||
|
* then this method is always called before
|
||||||
|
* {@link org.hibernate.boot.model.relational.ExportableProducer#registerExportables(Database)},
|
||||||
*
|
*
|
||||||
* @param type The id property type descriptor
|
* @param type The id property type descriptor
|
||||||
* @param params param values, keyed by parameter name
|
* @param params param values, keyed by parameter name
|
||||||
* @param serviceRegistry Access to service that may be needed.
|
* @param serviceRegistry Access to service that may be needed.
|
||||||
*/
|
*/
|
||||||
void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException;
|
void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this instance, pre-generating SQL if necessary.
|
||||||
|
* <p>
|
||||||
|
* If this instance also implements {@code ExportableProducer},
|
||||||
|
* then this method is always called after
|
||||||
|
* {@link org.hibernate.boot.model.relational.ExportableProducer#registerExportables(Database)},
|
||||||
|
* and before first use.
|
||||||
|
*
|
||||||
|
* @param context A context to help generate SQL strings
|
||||||
|
*/
|
||||||
|
default void initialize(SqlStringGenerationContext context) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,18 +113,6 @@ public interface IdentifierGenerator extends BeforeExecutionGenerator, Exportabl
|
||||||
@Override
|
@Override
|
||||||
default void registerExportables(Database database) {}
|
default void registerExportables(Database database) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes this instance, in particular pre-generates
|
|
||||||
* SQL as necessary.
|
|
||||||
* <p>
|
|
||||||
* This method is called after
|
|
||||||
* {@link #registerExportables(Database)},
|
|
||||||
* and before first use.
|
|
||||||
*
|
|
||||||
* @param context A context to help generate SQL strings
|
|
||||||
*/
|
|
||||||
default void initialize(SqlStringGenerationContext context) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new identifier.
|
* Generate a new identifier.
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,4 +15,8 @@ import org.hibernate.generator.GeneratorCreationContext;
|
||||||
public interface CustomIdGeneratorCreationContext extends GeneratorCreationContext {
|
public interface CustomIdGeneratorCreationContext extends GeneratorCreationContext {
|
||||||
IdentifierGeneratorFactory getIdentifierGeneratorFactory();
|
IdentifierGeneratorFactory getIdentifierGeneratorFactory();
|
||||||
RootClass getRootClass();
|
RootClass getRootClass();
|
||||||
|
|
||||||
|
// we could add these if it helps integrate old infrastructure
|
||||||
|
// Properties getParameters();
|
||||||
|
// SqlStringGenerationContext getSqlStringGenerationContext();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||||
import org.hibernate.event.spi.EventEngine;
|
import org.hibernate.event.spi.EventEngine;
|
||||||
import org.hibernate.generator.Generator;
|
import org.hibernate.generator.Generator;
|
||||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
|
import org.hibernate.id.Configurable;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||||
import org.hibernate.integrator.spi.Integrator;
|
import org.hibernate.integrator.spi.Integrator;
|
||||||
|
@ -466,8 +467,8 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
||||||
jdbcServices.getJdbcEnvironment().getDialect(),
|
jdbcServices.getJdbcEnvironment().getDialect(),
|
||||||
(RootClass) model
|
(RootClass) model
|
||||||
);
|
);
|
||||||
if ( generator instanceof IdentifierGenerator ) {
|
if ( generator instanceof Configurable ) {
|
||||||
final IdentifierGenerator identifierGenerator = (IdentifierGenerator) generator;
|
final Configurable identifierGenerator = (Configurable) generator;
|
||||||
identifierGenerator.initialize( sqlStringGenerationContext );
|
identifierGenerator.initialize( sqlStringGenerationContext );
|
||||||
}
|
}
|
||||||
if ( generator.allowAssignedIdentifiers() ) {
|
if ( generator.allowAssignedIdentifiers() ) {
|
||||||
|
|
|
@ -34,8 +34,8 @@ import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
|
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
|
||||||
|
import org.hibernate.id.Configurable;
|
||||||
import org.hibernate.id.IdentifierGenerationException;
|
import org.hibernate.id.IdentifierGenerationException;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
|
||||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
|
@ -784,8 +784,8 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(SqlStringGenerationContext context) {
|
public void initialize(SqlStringGenerationContext context) {
|
||||||
if ( subgenerator instanceof IdentifierGenerator ) {
|
if ( subgenerator instanceof Configurable) {
|
||||||
( (IdentifierGenerator) subgenerator).initialize( context );
|
( (Configurable) subgenerator).initialize( context );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,19 +405,20 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
IdentifierGeneratorFactory identifierGeneratorFactory,
|
IdentifierGeneratorFactory identifierGeneratorFactory,
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
RootClass rootClass) throws MappingException {
|
RootClass rootClass) throws MappingException {
|
||||||
if ( generator != null ) {
|
getTable().setIdentifierValue( this );
|
||||||
return generator;
|
|
||||||
}
|
if ( generator == null ) {
|
||||||
else if ( customIdGeneratorCreator != null ) {
|
if ( customIdGeneratorCreator != null ) {
|
||||||
generator = customIdGeneratorCreator.createGenerator(
|
generator = customIdGeneratorCreator.createGenerator(
|
||||||
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
|
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
|
||||||
);
|
);
|
||||||
return generator;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
generator = createLegacyIdentifierGenerator(this, identifierGeneratorFactory, dialect, null, null, rootClass );
|
||||||
generator = createLegacyIdentifierGenerator(this, identifierGeneratorFactory, dialect, null, null, rootClass );
|
}
|
||||||
return generator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUpdateable() {
|
public boolean isUpdateable() {
|
||||||
|
@ -1134,5 +1135,22 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
public Property getProperty() {
|
public Property getProperty() {
|
||||||
return rootClass.getIdentifierProperty();
|
return rootClass.getIdentifierProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we could add these if it helps integrate old infrastructure
|
||||||
|
// @Override
|
||||||
|
// public Properties getParameters() {
|
||||||
|
// final Value value = getProperty().getValue();
|
||||||
|
// if ( !value.isSimpleValue() ) {
|
||||||
|
// throw new IllegalStateException( "not a simple-valued property" );
|
||||||
|
// }
|
||||||
|
// final Dialect dialect = getDatabase().getDialect();
|
||||||
|
// return collectParameters( (SimpleValue) value, dialect, defaultCatalog, defaultSchema, rootClass );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public SqlStringGenerationContext getSqlStringGenerationContext() {
|
||||||
|
// final Database database = getDatabase();
|
||||||
|
// return fromExplicit( database.getJdbcEnvironment(), database, defaultCatalog, defaultSchema );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.SubselectFetch;
|
import org.hibernate.engine.spi.SubselectFetch;
|
||||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||||
import org.hibernate.generator.Generator;
|
import org.hibernate.generator.Generator;
|
||||||
|
import org.hibernate.id.Configurable;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.internal.FilterAliasGenerator;
|
import org.hibernate.internal.FilterAliasGenerator;
|
||||||
import org.hibernate.internal.FilterHelper;
|
import org.hibernate.internal.FilterHelper;
|
||||||
|
@ -605,8 +606,8 @@ public abstract class AbstractCollectionPersister
|
||||||
if ( generator.generatedOnExecution() ) {
|
if ( generator.generatedOnExecution() ) {
|
||||||
throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
|
throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
|
||||||
}
|
}
|
||||||
if ( generator instanceof IdentifierGenerator ) {
|
if ( generator instanceof Configurable ) {
|
||||||
( (IdentifierGenerator) generator ).initialize( context.getSqlStringGenerationContext() );
|
( (Configurable) generator ).initialize( context.getSqlStringGenerationContext() );
|
||||||
}
|
}
|
||||||
return (BeforeExecutionGenerator) generator;
|
return (BeforeExecutionGenerator) generator;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
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.OnExecutionGenerator;
|
||||||
|
import org.hibernate.id.Configurable;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||||
|
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
|
||||||
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
import org.hibernate.mapping.SimpleValue;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import java.lang.reflect.Member;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class NativeGenerator
|
||||||
|
implements OnExecutionGenerator, BeforeExecutionGenerator, Configurable, ExportableProducer {
|
||||||
|
|
||||||
|
private final IdentifierGeneratorFactory factory;
|
||||||
|
private final String strategy;
|
||||||
|
|
||||||
|
private Generator generator;
|
||||||
|
|
||||||
|
public NativeGenerator(NativeId nativeId, Member member, CustomIdGeneratorCreationContext creationContext) {
|
||||||
|
factory = creationContext.getIdentifierGeneratorFactory();
|
||||||
|
strategy = creationContext.getDatabase().getDialect().getNativeIdentifierGeneratorStrategy();
|
||||||
|
SimpleValue value = (SimpleValue) creationContext.getProperty().getValue();
|
||||||
|
value.setIdentifierGeneratorStrategy(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumSet<EventType> getEventTypes() {
|
||||||
|
return generator.getEventTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generatedOnExecution() {
|
||||||
|
return generator.generatedOnExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(Type type, Properties parameters, ServiceRegistry serviceRegistry) {
|
||||||
|
generator = factory.createIdentifierGenerator(strategy, type, parameters);
|
||||||
|
//TODO: should use this instead of the deprecated method, but see HHH-18135
|
||||||
|
// GenerationType generationType;
|
||||||
|
// switch (strategy) {
|
||||||
|
// case "identity":
|
||||||
|
// generationType = GenerationType.IDENTITY;
|
||||||
|
// break;
|
||||||
|
// case "sequence":
|
||||||
|
// generationType = GenerationType.SEQUENCE;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// throw new AssertionFailure("unrecognized strategy");
|
||||||
|
// }
|
||||||
|
// generator =
|
||||||
|
// factory.createIdentifierGenerator( generationType, strategy, strategy, type.getJavaTypeDescriptor(),
|
||||||
|
// parameters, (a, b) -> null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerExportables(Database database) {
|
||||||
|
if ( generator instanceof ExportableProducer ) {
|
||||||
|
((ExportableProducer) generator).registerExportables(database);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(SqlStringGenerationContext context) {
|
||||||
|
if ( generator instanceof Configurable ) {
|
||||||
|
((Configurable) generator).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(PostInsertIdentityPersister persister) {
|
||||||
|
return ((OnExecutionGenerator) generator).getGeneratedIdentifierDelegate(persister);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
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