From 415a27434fe572906699bc26e1c7226d2f6bd0ed Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Thu, 21 Mar 2024 15:21:01 +0100 Subject: [PATCH] HHH-17472 Move `allowAssignedIdentifiers()` up to `Generator` interface Also test with `@IdGeneratorType` --- .../org/hibernate/generator/Generator.java | 14 +++++ .../org/hibernate/id/IdentifierGenerator.java | 14 ----- .../internal/SessionFactoryImpl.java | 6 +- .../SequenceOrAssignedGeneratorTest.java | 61 ++++++++++++++++--- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/generator/Generator.java b/hibernate-core/src/main/java/org/hibernate/generator/Generator.java index a96c95c2a0..b0f91efe16 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/Generator.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/Generator.java @@ -132,6 +132,20 @@ public interface Generator extends Serializable { */ EnumSet getEventTypes(); + /** + * Determine if this generator allows identifier values to be manually assigned to the entity + * instance before persisting it. This is useful when, for example, needing existing assigned + * values to be used as identifiers and falling back to generated values by default. + * + * @return {@code true} if this generator allows pre-assigned identifier values, + * {@code false} otherwise (default). + * + * @since 6.5 + */ + default boolean allowAssignedIdentifiers() { + return false; + } + default boolean generatesSometimes() { return !getEventTypes().isEmpty(); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java index c93cbb7366..d33de987d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java @@ -155,20 +155,6 @@ public interface IdentifierGenerator extends BeforeExecutionGenerator, Exportabl return INSERT_ONLY; } - /** - * Determine if this generator allows identifier values to be manually assigned to the entity - * instance before persisting it. This is useful when, for example, needing existing assigned - * values to be used as identifiers and falling back to generated values by default. - * - * @return {@code true} if this generator allows pre-assigned identifier values, - * {@code false} otherwise (default). - * - * @since 6.5 - */ - default boolean allowAssignedIdentifiers() { - return false; - } - /** * Check if JDBC batch inserts are supported. * diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 7eb82ae223..7c4a376195 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -469,9 +469,9 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im if ( generator instanceof IdentifierGenerator ) { final IdentifierGenerator identifierGenerator = (IdentifierGenerator) generator; identifierGenerator.initialize( sqlStringGenerationContext ); - if ( identifierGenerator.allowAssignedIdentifiers() ) { - ( (SimpleValue) model.getIdentifier() ).setNullValue( "undefined" ); - } + } + if ( generator.allowAssignedIdentifiers() ) { + ( (SimpleValue) model.getIdentifier() ).setNullValue( "undefined" ); } generators.put( model.getEntityName(), generator ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/SequenceOrAssignedGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/SequenceOrAssignedGeneratorTest.java index 904d14ab9b..b4665d2184 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/SequenceOrAssignedGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/SequenceOrAssignedGeneratorTest.java @@ -6,9 +6,17 @@ */ package org.hibernate.orm.test.idgen.userdefined; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.EnumSet; + import org.hibernate.HibernateException; import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.IdGeneratorType; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.generator.BeforeExecutionGenerator; +import org.hibernate.generator.EventType; +import org.hibernate.generator.EventTypeSets; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.testing.jdbc.SQLStatementInspector; @@ -16,6 +24,7 @@ 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.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import jakarta.persistence.Entity; @@ -23,6 +32,9 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Version; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.assertj.core.api.Assertions.assertThat; /** @@ -212,12 +224,9 @@ public class SequenceOrAssignedGeneratorTest { } @Entity( name = "MyVersionedEntity" ) - @GenericGenerator( type = SequenceOrAssignedGenerator.class, name = MyVersionedEntity.SEQUENCE ) public static class MyVersionedEntity { - protected static final String SEQUENCE = "SEQ_MyVersionedEntity"; - @Id - @GeneratedValue( generator = SEQUENCE ) + @AssignedOrConstant private Long id; @Version @@ -252,17 +261,51 @@ public class SequenceOrAssignedGeneratorTest { if ( owner instanceof MyEntity ) { id = ( (MyEntity) owner ).getId(); } - else if ( owner instanceof MyVersionedEntity ) { + else { + id = null; + } + + return id != null ? id : super.generate( session, owner ); + } + + @Override + public boolean allowAssignedIdentifiers() { + return true; + } + } + + @IdGeneratorType( AssignedOrCountGenerator.class ) + @Target( { METHOD, FIELD } ) + @Retention( RUNTIME ) + public @interface AssignedOrConstant { + } + + public static class AssignedOrCountGenerator implements BeforeExecutionGenerator { + private Long count; + + public AssignedOrCountGenerator() { + this.count = 1L; + } + + @Override + public Object generate( + SharedSessionContractImplementor session, + Object owner, + Object currentValue, + EventType eventType) { + final Long id; + if ( owner instanceof MyVersionedEntity ) { id = ( (MyVersionedEntity) owner ).getId(); } else { id = null; } - if ( id != null ) { - return id; - } + return id != null ? id : count++; + } - return super.generate( session, owner ); + @Override + public EnumSet getEventTypes() { + return EventTypeSets.INSERT_ONLY; } @Override