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 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.type.Type;
|
||||
|
||||
|
@ -21,12 +23,30 @@ import org.hibernate.type.Type;
|
|||
public interface Configurable {
|
||||
/**
|
||||
* 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.
|
||||
* 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 params param values, keyed by parameter name
|
||||
* @param serviceRegistry Access to service that may be needed.
|
||||
*/
|
||||
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
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -15,4 +15,8 @@ import org.hibernate.generator.GeneratorCreationContext;
|
|||
public interface CustomIdGeneratorCreationContext extends GeneratorCreationContext {
|
||||
IdentifierGeneratorFactory getIdentifierGeneratorFactory();
|
||||
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.generator.Generator;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||
import org.hibernate.integrator.spi.Integrator;
|
||||
|
@ -466,8 +467,8 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
jdbcServices.getJdbcEnvironment().getDialect(),
|
||||
(RootClass) model
|
||||
);
|
||||
if ( generator instanceof IdentifierGenerator ) {
|
||||
final IdentifierGenerator identifierGenerator = (IdentifierGenerator) generator;
|
||||
if ( generator instanceof Configurable ) {
|
||||
final Configurable identifierGenerator = (Configurable) generator;
|
||||
identifierGenerator.initialize( sqlStringGenerationContext );
|
||||
}
|
||||
if ( generator.allowAssignedIdentifiers() ) {
|
||||
|
|
|
@ -34,8 +34,8 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentifierGenerationException;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
@ -784,8 +784,8 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
|
||||
@Override
|
||||
public void initialize(SqlStringGenerationContext context) {
|
||||
if ( subgenerator instanceof IdentifierGenerator ) {
|
||||
( (IdentifierGenerator) subgenerator).initialize( context );
|
||||
if ( subgenerator instanceof Configurable) {
|
||||
( (Configurable) subgenerator).initialize( context );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,19 +405,20 @@ public abstract class SimpleValue implements KeyValue {
|
|||
IdentifierGeneratorFactory identifierGeneratorFactory,
|
||||
Dialect dialect,
|
||||
RootClass rootClass) throws MappingException {
|
||||
if ( generator != null ) {
|
||||
return generator;
|
||||
}
|
||||
else if ( customIdGeneratorCreator != null ) {
|
||||
generator = customIdGeneratorCreator.createGenerator(
|
||||
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
|
||||
);
|
||||
return generator;
|
||||
}
|
||||
else {
|
||||
generator = createLegacyIdentifierGenerator(this, identifierGeneratorFactory, dialect, null, null, rootClass );
|
||||
return generator;
|
||||
getTable().setIdentifierValue( this );
|
||||
|
||||
if ( generator == null ) {
|
||||
if ( customIdGeneratorCreator != null ) {
|
||||
generator = customIdGeneratorCreator.createGenerator(
|
||||
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
|
||||
);
|
||||
}
|
||||
else {
|
||||
generator = createLegacyIdentifierGenerator(this, identifierGeneratorFactory, dialect, null, null, rootClass );
|
||||
}
|
||||
}
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
public boolean isUpdateable() {
|
||||
|
@ -1134,5 +1135,22 @@ public abstract class SimpleValue implements KeyValue {
|
|||
public Property getProperty() {
|
||||
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.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.internal.FilterAliasGenerator;
|
||||
import org.hibernate.internal.FilterHelper;
|
||||
|
@ -605,8 +606,8 @@ public abstract class AbstractCollectionPersister
|
|||
if ( generator.generatedOnExecution() ) {
|
||||
throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
|
||||
}
|
||||
if ( generator instanceof IdentifierGenerator ) {
|
||||
( (IdentifierGenerator) generator ).initialize( context.getSqlStringGenerationContext() );
|
||||
if ( generator instanceof Configurable ) {
|
||||
( (Configurable) generator ).initialize( context.getSqlStringGenerationContext() );
|
||||
}
|
||||
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