HHH-15800 introduce EventType + EventTypeSets in place of the previous "two booleans" approach

I hope @sebersole likes this better.

re-deprecate GenerationTime since the way forward is EventType
This commit is contained in:
Gavin 2022-12-03 21:29:25 +01:00 committed by Gavin King
parent c09664711d
commit 0228c3d185
28 changed files with 272 additions and 229 deletions

View File

@ -10,6 +10,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.hibernate.Remove;
import org.hibernate.generator.EventType;
import org.hibernate.generator.internal.CurrentTimestampGeneration;
import org.hibernate.tuple.GenerationTiming;
@ -17,6 +18,8 @@ import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
/**
* Specifies that the annotated field of property is a generated timestamp,
@ -68,9 +71,9 @@ public @interface CurrentTimestamp {
* Determines when the timestamp is generated. But default, it is updated
* when any SQL {@code insert} or {@code update} statement is executed.
* If it should be generated just once, on the initial SQL {@code insert},
* explicitly specify {@link GenerationTime#INSERT event = INSERT}.
* explicitly specify {@link EventType#INSERT event = INSERT}.
*/
GenerationTime event() default GenerationTime.INSERT_OR_UPDATE;
EventType[] event() default {INSERT, UPDATE};
/**
* Determines when the timestamp is generated. But default, it is updated

View File

@ -11,8 +11,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hibernate.generator.EventType;
import org.hibernate.generator.internal.GeneratedGeneration;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
/**
* Specifies that the value of the annotated property is generated by the
* database. The generated value will be automatically retrieved using a
@ -59,16 +63,15 @@ public @interface Generated {
* Specifies the events that cause the value to be generated by the
* database.
* <ul>
* <li>If {@link GenerationTime#INSERT}, the generated value will be
* selected after each SQL {@code insert} statement is executed.
* <li>If {@link GenerationTime#UPDATE}, the generated value will be
* selected after each SQL {@code update} statement is executed.
* <li>If {@link GenerationTime#INSERT_OR_UPDATE}, the generated value
* will be selected after each SQL {@code insert} or {@code update}
* statement is executed.
* <li>If {@link EventType#INSERT} is included, the generated value
* will be selected after each SQL {@code insert} statement is
* executed.
* <li>If {@link EventType#UPDATE} is included, the generated value
* will be selected after each SQL {@code update} statement is
* executed.
* </ul>
*/
GenerationTime event() default GenerationTime.INSERT_OR_UPDATE;
EventType[] event() default {INSERT, UPDATE};
/**
* Specifies the events that cause the value to be generated by the

View File

@ -8,8 +8,12 @@ package org.hibernate.annotations;
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.tuple.GenerationTiming;
import java.util.EnumSet;
/**
* Represents a class of events involving interaction with the database
* that causes generation of a new value. Intended for use with the
@ -19,7 +23,10 @@ import org.hibernate.tuple.GenerationTiming;
*
* @see Generated
* @see CurrentTimestamp
*
* @deprecated use {@link EventType} and {@link EventTypeSets} instead
*/
@Deprecated(since = "6.2")
public enum GenerationTime {
/**
* Indicates that a value is never generated.
@ -37,30 +44,22 @@ public enum GenerationTime {
UPDATE,
/**
* Indicates that a new value is generated on insert and on update.
*
* @since 6.2
*/
INSERT_OR_UPDATE,
/**
* Indicates that a new value is generated on insert and on update.
*
* @deprecated use {@link #INSERT_OR_UPDATE}
*/
@Deprecated(since = "6.2")
ALWAYS;
/**
* @return {@code true} if a new value is generated when an insert is executed
*/
public boolean includesInsert() {
return getEquivalent().includesInsert();
}
/**
* @return {@code true} if a new value is generated when an update is executed
*/
public boolean includesUpdate() {
return getEquivalent().includesUpdate();
public EnumSet<EventType> eventTypes() {
switch (this) {
case NEVER:
return EventTypeSets.NONE;
case ALWAYS:
return EventTypeSets.ALL;
case INSERT:
return EventTypeSets.INSERT_ONLY;
case UPDATE:
return EventTypeSets.UPDATE_ONLY;
default:
throw new AssertionFailure("unknown event");
}
}
/**
@ -70,7 +69,6 @@ public enum GenerationTime {
public GenerationTiming getEquivalent() {
switch (this) {
case ALWAYS:
case INSERT_OR_UPDATE:
return GenerationTiming.ALWAYS;
case INSERT:
return GenerationTiming.INSERT;

View File

@ -572,12 +572,12 @@ public class PropertyBinder {
private static void checkVersionGenerationAlways(XProperty property, Generator generator) {
if ( property.isAnnotationPresent(Version.class) ) {
if ( !generator.generatedOnInsert() ) {
if ( !generator.generatesOnInsert() ) {
throw new AnnotationException("Property '" + property.getName()
+ "' is annotated '@Version' but has a 'Generator' which does not generate on inserts"
);
}
if ( !generator.generatedOnUpdate() ) {
if ( !generator.generatesOnUpdate() ) {
throw new AnnotationException("Property '" + property.getName()
+ "' is annotated '@Version' but has a 'Generator' which does not generate on updates"
);
@ -586,11 +586,11 @@ public class PropertyBinder {
}
private static void checkIdGeneratorTiming(Class<? extends Annotation> annotationType, Generator generator) {
if ( !generator.generatedOnInsert() ) {
if ( !generator.generatesOnInsert() ) {
throw new MappingException( "Annotation '" + annotationType
+ "' is annotated 'IdGeneratorType' but the given 'Generator' does not generate on inserts");
}
if ( generator.generatedOnUpdate() ) {
if ( generator.generatesOnUpdate() ) {
throw new MappingException( "Annotation '" + annotationType
+ "' is annotated 'IdGeneratorType' but the given 'Generator' generates on updates (it must generate only on inserts)");
}

View File

@ -129,7 +129,7 @@ public final class Nullability {
}
private static boolean generated(Generator generator) {
return generator != null && generator.isNotNever();
return generator != null && generator.generatesSometimes();
}
/**

View File

@ -0,0 +1,29 @@
/*
* 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.generator;
/**
* Enumerates event types that can result in generation of a new value.
* A {@link Generator} must specify which events it responds to, by
* implementing {@link Generator#getEventTypes()}.
* <p>
* We usually work with {@linkplain EventTypeSets sets} of event types,
* even though there are only two types.
*
* @author Gavin King
*
* @since 6.2
*
* @see Generator
* @see org.hibernate.annotations.Generated
* @see org.hibernate.annotations.CurrentTimestamp
* @see EventTypeSets
*/
public enum EventType {
INSERT,
UPDATE;
}

View File

@ -0,0 +1,35 @@
/*
* 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.generator;
import java.util.EnumSet;
import java.util.Set;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
/**
* For convenience, enumerates the possible combinations of {@link EventType}.
* <p>
* This list supersedes the enumerations {@link org.hibernate.annotations.GenerationTime}
* and {@link org.hibernate.tuple.GenerationTiming} from older versions of Hibernate.
*
* @author Gavin King
*
* @since 6.2
*/
public class EventTypeSets {
public static final EnumSet<EventType> NONE = EnumSet.noneOf(EventType.class);
public static final EnumSet<EventType> INSERT_ONLY = EnumSet.of(INSERT);
public static final EnumSet<EventType> UPDATE_ONLY = EnumSet.of(UPDATE);
public static final EnumSet<EventType> INSERT_AND_UPDATE = EnumSet.of(INSERT, UPDATE);
public static final EnumSet<EventType> ALL = EnumSet.allOf(EventType.class);
public static EnumSet<EventType> fromArray(EventType[] types) {
return EnumSet.copyOf( Set.of(types) );
}
}

View File

@ -10,6 +10,10 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tuple.ValueGenerator;
import java.io.Serializable;
import java.util.EnumSet;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
/**
* Describes the generation of values of a certain field or property of an entity. A generated
@ -38,6 +42,14 @@ import java.io.Serializable;
* <li>declare a constructor which accepts just the annotation instance, or
* <li>declare a only default constructor, in which case it will not receive parameters.
* </ul>
* A generator must implement {@link #getEventTypes()} to specify the events for which it should be
* called to produce a new value. {@link EventTypeSets} provides a convenient list of possibilities.
* <p>
* An {@linkplain jakarta.persistence.Id identifier} generator is a generator capable of producing
* surrogate primary key values. An identifier generator must respond to insert events only. That
* is, {@link #getEventTypes()} must return {@link EventTypeSets#INSERT_ONLY}. It may be integrated
* using the {@link org.hibernate.annotations.IdGeneratorType} meta-annotation or the older-style
* {@link org.hibernate.annotations.GenericGenerator} annotation.
*
* @see org.hibernate.annotations.ValueGenerationType
* @see org.hibernate.annotations.IdGeneratorType
@ -57,11 +69,25 @@ public interface Generator extends Serializable {
*/
boolean generatedByDatabase();
boolean generatedOnInsert();
/**
* The {@linkplain EventType event types} for which this generator should be called
* to produce a new value.
* <p>
* Identifier generators must return {@link EventTypeSets#INSERT_ONLY}.
*
* @return a set of {@link EventType}s.
*/
EnumSet<EventType> getEventTypes();
boolean generatedOnUpdate();
default boolean generatesSometimes() {
return !getEventTypes().isEmpty();
}
default boolean isNotNever() {
return generatedOnInsert() || generatedOnUpdate();
default boolean generatesOnInsert() {
return getEventTypes().contains(INSERT);
}
default boolean generatesOnUpdate() {
return getEventTypes().contains(UPDATE);
}
}

View File

@ -7,7 +7,6 @@
package org.hibernate.generator;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tuple.GenerationTiming;
/**
* A generator that is called to produce a value just before a row is written to the database.
@ -16,8 +15,8 @@ import org.hibernate.tuple.GenerationTiming;
* database via a parameter of a JDBC prepared statement, just like any other field or property
* value.
* <p>
* Any {@link InMemoryGenerator} with {@linkplain #getGenerationTiming() generation timing}
* {@link GenerationTiming#INSERT} may be used to produce {@linkplain jakarta.persistence.Id
* Any {@link InMemoryGenerator} with {@linkplain #getEventTypes() generation event types}
* {@link EventTypeSets#INSERT_ONLY} may be used to produce {@linkplain jakarta.persistence.Id
* identifiers}. The built-in identifier generators all implement the older extension point
* {@link org.hibernate.id.IdentifierGenerator}, which is a subtype of this interface, but that
* is no longer a requirement for custom id generators.

View File

@ -10,22 +10,25 @@ import org.hibernate.AssertionFailure;
import org.hibernate.Session;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.CurrentTimestamp;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.annotations.SourceType;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.InDatabaseGenerator;
import org.hibernate.generator.InMemoryGenerator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.generator.GeneratorCreationContext;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.TimestampGenerators;
import org.hibernate.tuple.ValueGenerator;
import java.lang.reflect.Member;
import java.util.EnumSet;
import static org.hibernate.annotations.GenerationTime.INSERT;
import static org.hibernate.annotations.GenerationTime.INSERT_OR_UPDATE;
import static org.hibernate.generator.EventTypeSets.INSERT_AND_UPDATE;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
import static org.hibernate.generator.EventTypeSets.fromArray;
/**
* Value generation strategy which produces a timestamp using the database
@ -45,22 +48,24 @@ import static org.hibernate.annotations.GenerationTime.INSERT_OR_UPDATE;
* @author Gavin King
*/
public class CurrentTimestampGeneration implements InMemoryGenerator, InDatabaseGenerator {
private final GenerationTime timing;
private final EnumSet<EventType> eventTypes;
private final ValueGenerator<?> generator;
public CurrentTimestampGeneration(CurrentTimestamp annotation, Member member, GeneratorCreationContext context) {
generator = getGenerator( annotation.source(), member );
timing = annotation.event() == INSERT_OR_UPDATE ? annotation.timing().getEquivalent() : annotation.event();
eventTypes = annotation.timing() == GenerationTiming.ALWAYS
? fromArray( annotation.event() )
: annotation.timing().getEquivalent().eventTypes();
}
public CurrentTimestampGeneration(CreationTimestamp annotation, Member member, GeneratorCreationContext context) {
generator = getGenerator( annotation.source(), member );
timing = INSERT;
eventTypes = INSERT_ONLY;
}
public CurrentTimestampGeneration(UpdateTimestamp annotation, Member member, GeneratorCreationContext context) {
generator = getGenerator( annotation.source(), member );
timing = INSERT_OR_UPDATE;
eventTypes = INSERT_AND_UPDATE;
}
private static ValueGenerator<?> getGenerator(SourceType source, Member member) {
@ -81,13 +86,8 @@ public class CurrentTimestampGeneration implements InMemoryGenerator, InDatabase
}
@Override
public boolean generatedOnInsert() {
return timing.includesInsert();
}
@Override
public boolean generatedOnUpdate() {
return timing.includesUpdate();
public EnumSet<EventType> getEventTypes() {
return eventTypes;
}
@Override

View File

@ -8,8 +8,13 @@ package org.hibernate.generator.internal;
import org.hibernate.annotations.GeneratedColumn;
import org.hibernate.dialect.Dialect;
import org.hibernate.generator.EventType;
import org.hibernate.generator.InDatabaseGenerator;
import java.util.EnumSet;
import static org.hibernate.generator.EventTypeSets.ALL;
/**
* For {@link GeneratedColumn}.
*
@ -20,13 +25,8 @@ public class GeneratedAlwaysGeneration implements InDatabaseGenerator {
public GeneratedAlwaysGeneration() {}
@Override
public boolean generatedOnUpdate() {
return true;
}
@Override
public boolean generatedOnInsert() {
return true;
public EnumSet<EventType> getEventTypes() {
return ALL;
}
@Override

View File

@ -9,45 +9,46 @@ package org.hibernate.generator.internal;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.dialect.Dialect;
import org.hibernate.generator.EventType;
import org.hibernate.generator.InDatabaseGenerator;
import org.hibernate.tuple.AnnotationValueGeneration;
import static org.hibernate.annotations.GenerationTime.INSERT_OR_UPDATE;
import java.util.EnumSet;
import static org.hibernate.generator.EventTypeSets.fromArray;
import static org.hibernate.internal.util.StringHelper.isEmpty;
/**
* A {@link AnnotationValueGeneration} which marks a property as generated in the database.
* A fairly generic {@link InDatabaseGenerator} which marks a property as generated in the
* database with semantics given explicitly by a {@link Generated @Generated} annotation.
*
* @see Generated
*
* @author Steve Ebersole
* @author Gunnar Morling
*/
public class GeneratedGeneration implements InDatabaseGenerator {
private GenerationTime timing;
private boolean writable;
private String[] sql;
public GeneratedGeneration() {
}
private final EnumSet<EventType> eventTypes;
private final boolean writable;
private final String[] sql;
public GeneratedGeneration(GenerationTime event) {
this.timing = event;
eventTypes = event.eventTypes();
writable = false;
sql = null;
}
public GeneratedGeneration(Generated annotation) {
timing = annotation.event() == INSERT_OR_UPDATE ? annotation.value() : annotation.event();
eventTypes = annotation.value() == GenerationTime.ALWAYS
? fromArray( annotation.event() )
: annotation.value().eventTypes();
sql = isEmpty( annotation.sql() ) ? null : new String[] { annotation.sql() };
writable = annotation.writable() || sql != null;
}
@Override
public boolean generatedOnInsert() {
return timing.includesInsert();
}
@Override
public boolean generatedOnUpdate() {
return timing.includesUpdate();
public EnumSet<EventType> getEventTypes() {
return eventTypes;
}
@Override

View File

@ -14,6 +14,8 @@ import org.hibernate.annotations.SourceType;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.generator.GeneratorCreationContext;
import org.hibernate.generator.InMemoryGenerator;
import org.hibernate.internal.CoreMessageLogger;
@ -27,8 +29,10 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.EnumSet;
import static java.sql.Types.TIMESTAMP;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
/**
* Value generation strategy using the query {@link Dialect#getCurrentTimestampSelectString()}.
@ -77,19 +81,11 @@ public class SourceGeneration implements InMemoryGenerator {
}
/**
* @return {@code true}
* @return {@link EventTypeSets#INSERT_ONLY}
*/
@Override
public boolean generatedOnInsert() {
return true;
}
/**
* @return {@code false}
*/
@Override
public boolean generatedOnUpdate() {
return false;
public EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
@Override

View File

@ -12,12 +12,16 @@ import org.hibernate.annotations.TenantId;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.generator.InMemoryGenerator;
import org.hibernate.generator.GeneratorCreationContext;
import org.hibernate.type.descriptor.java.JavaType;
import java.lang.reflect.Member;
import java.util.EnumSet;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
import static org.hibernate.internal.util.ReflectHelper.getPropertyType;
/**
@ -39,19 +43,11 @@ public class TenantIdGeneration implements InMemoryGenerator {
}
/**
* @return {@code true}
* @return {@link EventTypeSets#INSERT_ONLY}
*/
@Override
public boolean generatedOnInsert() {
return true;
}
/**
* @return {@code false}
*/
@Override
public boolean generatedOnUpdate() {
return false;
public EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
@Override

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.id;
import java.util.EnumSet;
import java.util.Properties;
import org.hibernate.HibernateException;
@ -14,15 +15,18 @@ import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.generator.InMemoryGenerator;
import org.hibernate.type.Type;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
/**
* A classic extension point from the very earliest days of Hibernate,
* this interface is no longer the only way to generate identifiers. Any
* {@link InMemoryGenerator} with timing {@link GenerationTiming#INSERT}
* {@link InMemoryGenerator} with timing {@link EventTypeSets#INSERT_ONLY}
* may now be used.
* <p>
* This interface extends {@code InMemoryGenerator} with some additional
@ -143,19 +147,11 @@ public interface IdentifierGenerator extends InMemoryGenerator, ExportableProduc
}
/**
* @return {@code true}
* @return {@link EventTypeSets#INSERT_ONLY}
*/
@Override
default boolean generatedOnInsert() {
return true;
}
/**
* @return {@code false}
*/
@Override
default boolean generatedOnUpdate() {
return false;
default EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
/**

View File

@ -6,17 +6,21 @@
*/
package org.hibernate.id;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.generator.InDatabaseGenerator;
import org.hibernate.type.Type;
import java.util.EnumSet;
import java.util.Properties;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
/**
* The counterpart of {@link IdentifierGenerator} for values generated by the database.
* This interface is no longer the only way to handle database-generate identifiers.
* Any {@link InDatabaseGenerator} with timing {@link GenerationTiming#INSERT} may now
* Any {@link InDatabaseGenerator} with timing {@link EventTypeSets#INSERT_ONLY} may now
* be used.
*
* @see IdentifierGenerator
@ -26,19 +30,11 @@ import java.util.Properties;
public interface PostInsertIdentifierGenerator extends InDatabaseGenerator, Configurable {
/**
* @return {@code true}
* @return {@link EventTypeSets#INSERT_ONLY}
*/
@Override
default boolean generatedOnInsert() {
return true;
}
/**
* @return {@code false}
*/
@Override
default boolean generatedOnUpdate() {
return false;
default EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
/**

View File

@ -7,16 +7,20 @@
package org.hibernate.id.uuid;
import java.lang.reflect.Member;
import java.util.EnumSet;
import java.util.UUID;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.EventTypeSets;
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
import org.hibernate.generator.InMemoryGenerator;
import org.hibernate.type.descriptor.java.UUIDJavaType;
import org.hibernate.type.descriptor.java.UUIDJavaType.ValueTransformer;
import static org.hibernate.annotations.UuidGenerator.Style.TIME;
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
import static org.hibernate.internal.util.ReflectHelper.getPropertyType;
/**
@ -60,19 +64,11 @@ public class UuidGenerator implements InMemoryGenerator {
}
/**
* @return {@code true}
* @return {@link EventTypeSets#INSERT_ONLY}
*/
@Override
public boolean generatedOnInsert() {
return true;
}
/**
* @return {@code false}
*/
@Override
public boolean generatedOnUpdate() {
return false;
public EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
@Override

View File

@ -97,7 +97,7 @@ public class GeneratedValuesProcessor {
final Generator generator = generators[ mapping.getStateArrayPosition() ];
if ( generator != null
&& generator.generatedByDatabase()
&& generator.isNotNever() ) {
&& generator.generatesSometimes() ) {
// this attribute is generated for the timing we are processing...
valueDescriptors.add( new GeneratedValueDescriptor(
new InDatabaseGeneratedValueResolver( timing, generatedValuesToSelect.size() ),

View File

@ -2773,7 +2773,7 @@ public abstract class AbstractEntityPersister
else {
final Generator generator = attributeMapping.getGenerator();
if ( generator!=null
&& generator.generatedOnUpdate()
&& generator.generatesOnUpdate()
&& generator.generatedByDatabase() ) {
final InDatabaseGenerator databaseGenerator = (InDatabaseGenerator) generator;
final Dialect dialect = getFactory().getJdbcServices().getDialect();

View File

@ -106,7 +106,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
Generator generator = generators[i];
if ( generator != null
&& !generator.generatedByDatabase()
&& generator.generatedOnInsert() ) {
&& generator.generatesOnInsert() ) {
values[i] = ( (InMemoryGenerator) generator ).generate( session, entity, values[i] );
entityPersister().setPropertyValue( entity, i, values[i] );
}
@ -438,7 +438,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
return generator != null
&& generator.generatedOnInsert()
&& generator.generatesOnInsert()
&& generator.generatedByDatabase()
&& ( (InDatabaseGenerator) generator ).referenceColumnsInSql(dialect);
}

View File

@ -337,14 +337,14 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
private boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
return generator != null
&& generator.generatedOnUpdate()
&& generator.generatesOnUpdate()
&& generator.generatedByDatabase()
&& ((InDatabaseGenerator) generator).referenceColumnsInSql(dialect);
}
private boolean isValueGenerationInSqlNoWrite(Generator generator, Dialect dialect) {
return generator != null
&& generator.generatedOnUpdate()
&& generator.generatesOnUpdate()
&& generator.generatedByDatabase()
&& ((InDatabaseGenerator) generator).referenceColumnsInSql(dialect)
&& !((InDatabaseGenerator) generator).writePropertyValue();
@ -451,7 +451,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
Generator generator = generators[i];
if ( generator != null
&& !generator.generatedByDatabase()
&& generator.generatedOnUpdate() ) {
&& generator.generatesOnUpdate() ) {
newValues[i] = ( (InMemoryGenerator) generator ).generate( session, object, newValues[i] );
entityPersister().setPropertyValue( object, i, newValues[i] );
fieldsPreUpdateNeeded[count++] = i;

View File

@ -84,7 +84,7 @@ public enum GenerationTiming {
public GenerationTime getEquivalent() {
switch (this) {
case ALWAYS:
return GenerationTime.INSERT_OR_UPDATE;
return GenerationTime.ALWAYS;
case INSERT:
return GenerationTime.INSERT;
case UPDATE:

View File

@ -9,10 +9,13 @@ package org.hibernate.tuple;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.Generator;
import org.hibernate.generator.InDatabaseGenerator;
import org.hibernate.generator.InMemoryGenerator;
import java.util.EnumSet;
/**
* A value generator that can adapt to both Java value generation and database value generation.
* <p>
@ -39,13 +42,8 @@ public interface ValueGeneration extends InMemoryGenerator, InDatabaseGenerator
GenerationTiming getGenerationTiming();
@Override
default boolean generatedOnInsert() {
return getGenerationTiming().includesInsert();
}
@Override
default boolean generatedOnUpdate() {
return getGenerationTiming().includesUpdate();
default EnumSet<EventType> getEventTypes() {
return getGenerationTiming().getEquivalent().eventTypes();
}
/**

View File

@ -7,13 +7,14 @@
package org.hibernate.tuple;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.Session;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.annotations.GeneratorType;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.InMemoryGenerator;
import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor;
@ -30,7 +31,7 @@ import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor;
@Deprecated(since = "6.2")
public class VmValueGeneration implements InMemoryGenerator {
private final GenerationTime timing;
private final EnumSet<EventType> eventTypes;
private final ValueGenerator<?> generator;
public VmValueGeneration(GeneratorType annotation) {
@ -41,26 +42,14 @@ public class VmValueGeneration implements InMemoryGenerator {
catch (Exception e) {
throw new HibernateException( "Couldn't instantiate value generator", e );
}
timing = annotation.when();
eventTypes = annotation.when().eventTypes();
}
/**
* @return {@code true}
*/
@Override
public boolean generatedOnInsert() {
return timing.includesInsert();
public EnumSet<EventType> getEventTypes() {
return eventTypes;
}
/**
* @return {@code false}
*/
@Override
public boolean generatedOnUpdate() {
return timing.includesUpdate();
}
@Override
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
return generator.generateValue( (Session) session, owner, currentValue );

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -29,6 +30,7 @@ import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
@ -56,6 +58,7 @@ import org.hibernate.type.EntityType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
import static org.hibernate.generator.EventTypeSets.NONE;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
@ -309,7 +312,7 @@ public class EntityMetamodel implements Serializable {
propertyInsertability[i] = false;
propertyUpdateability[i] = false;
}
if ( generator.generatedOnInsert() ) {
if ( generator.generatesOnInsert() ) {
if ( generator.generatedByDatabase() ) {
foundPostInsertGeneratedValues = true;
}
@ -317,7 +320,7 @@ public class EntityMetamodel implements Serializable {
foundPreInsertGeneratedValues = true;
}
}
if ( generator.generatedOnUpdate() ) {
if ( generator.generatesOnUpdate() ) {
if ( generator.generatedByDatabase() ) {
foundPostUpdateGeneratedValues = true;
}
@ -454,7 +457,7 @@ public class EntityMetamodel implements Serializable {
final GeneratorCreator generatorCreator = mappingProperty.getValueGeneratorCreator();
if ( generatorCreator != null ) {
final Generator generator = mappingProperty.createGenerator( context );
if ( generator.isNotNever() ) {
if ( generator.generatesSometimes() ) {
return generator;
}
}
@ -510,7 +513,7 @@ public class EntityMetamodel implements Serializable {
}
private void add(InMemoryGenerator inMemoryStrategy) {
if ( inMemoryStrategy.isNotNever() ) {
if ( inMemoryStrategy.generatesSometimes() ) {
hadInMemoryGeneration = true;
}
}
@ -521,7 +524,7 @@ public class EntityMetamodel implements Serializable {
}
inDatabaseStrategies.add( inDatabaseStrategy );
if ( inDatabaseStrategy.isNotNever() ) {
if ( inDatabaseStrategy.generatesSometimes() ) {
hadInDatabaseGeneration = true;
}
}
@ -549,8 +552,7 @@ public class EntityMetamodel implements Serializable {
}
// the base-line values for the aggregated InDatabaseValueGenerationStrategy we will build here.
boolean generatedOnInsert = false;
boolean generatedOnUpdate = false;
EnumSet<EventType> eventTypes = EnumSet.noneOf(EventType.class);
boolean referenceColumns = false;
String[] columnValues = new String[ composite.getColumnSpan() ];
@ -559,15 +561,14 @@ public class EntityMetamodel implements Serializable {
int columnIndex = 0;
for ( Property property : composite.getProperties() ) {
propertyIndex++;
final InDatabaseGenerator subStrategy = inDatabaseStrategies.get( propertyIndex );
generatedOnUpdate = generatedOnUpdate || subStrategy.generatedOnUpdate();
generatedOnInsert = generatedOnInsert || subStrategy.generatedOnInsert();
if ( subStrategy.referenceColumnsInSql(dialect) ) {
final InDatabaseGenerator generator = inDatabaseStrategies.get( propertyIndex );
eventTypes.addAll( generator.getEventTypes() );
if ( generator.referenceColumnsInSql(dialect) ) {
// override base-line value
referenceColumns = true;
}
if ( subStrategy.getReferencedColumnValues(dialect) != null ) {
if ( subStrategy.getReferencedColumnValues(dialect).length != property.getColumnSpan() ) {
if ( generator.getReferencedColumnValues(dialect) != null ) {
if ( generator.getReferencedColumnValues(dialect).length != property.getColumnSpan() ) {
throw new ValueGenerationStrategyException(
"Internal error : mismatch between number of collected 'referenced column values'" +
" and number of columns for composite attribute : " + mappingProperty.getName() +
@ -575,7 +576,7 @@ public class EntityMetamodel implements Serializable {
);
}
System.arraycopy(
subStrategy.getReferencedColumnValues(dialect),
generator.getReferencedColumnValues(dialect),
0,
columnValues,
columnIndex,
@ -585,19 +586,14 @@ public class EntityMetamodel implements Serializable {
}
// then use the aggregated values to build the InDatabaseValueGenerationStrategy
return new InDatabaseGeneratorImpl( generatedOnUpdate, generatedOnInsert, referenceColumns, columnValues );
return new InDatabaseGeneratorImpl( eventTypes, referenceColumns, columnValues );
}
else {
return new Generator() {
@Override
public boolean generatedOnInsert() {
return false;
public EnumSet<EventType> getEventTypes() {
return NONE;
}
@Override
public boolean generatedOnUpdate() {
return false;
}
@Override
public boolean generatedByDatabase() {
return false;
}
@ -607,30 +603,22 @@ public class EntityMetamodel implements Serializable {
}
private static class InDatabaseGeneratorImpl implements InDatabaseGenerator {
private final boolean generatedOnUpdate;
private final boolean generatedOnInsert;
private final EnumSet<EventType> eventTypes;
private final boolean referenceColumnInSql;
private final String[] referencedColumnValues;
private InDatabaseGeneratorImpl(
boolean generatedOnUpdate,
boolean generatedOnInsert,
EnumSet<EventType> eventTypes,
boolean referenceColumnInSql,
String[] referencedColumnValues) {
this.generatedOnUpdate = generatedOnUpdate;
this.generatedOnInsert = generatedOnInsert;
this.eventTypes = eventTypes;
this.referenceColumnInSql = referenceColumnInSql;
this.referencedColumnValues = referencedColumnValues;
}
@Override
public boolean generatedOnInsert() {
return generatedOnInsert;
}
@Override
public boolean generatedOnUpdate() {
return generatedOnUpdate;
public EnumSet<EventType> getEventTypes() {
return eventTypes;
}
@Override
@ -672,17 +660,17 @@ public class EntityMetamodel implements Serializable {
// * That code checks that there is a natural identifier before making this call, so we assume the same here
// * That code assumes a non-composite natural-id, so we assume the same here
final Generator strategy = generators[ naturalIdPropertyNumbers[0] ];
return strategy != null && strategy.isNotNever();
return strategy != null && strategy.generatesSometimes();
}
public boolean isVersionGeneratedByDatabase() {
final Generator strategy = generators[ versionPropertyIndex ];
return strategy != null && strategy.isNotNever() && strategy.generatedByDatabase();
return strategy != null && strategy.generatesSometimes() && strategy.generatedByDatabase();
}
public boolean isVersionGeneratedInMemory() {
final Generator strategy = generators[ versionPropertyIndex ];
return strategy != null && strategy.isNotNever() && !strategy.generatedByDatabase();
return strategy != null && strategy.generatesSometimes() && !strategy.generatedByDatabase();
}
public int[] getNaturalIdentifierProperties() {

View File

@ -22,8 +22,8 @@ import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hibernate.annotations.GenerationTime.INSERT;
import static org.hibernate.annotations.GenerationTime.INSERT_OR_UPDATE;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
/**
* @author Steve Ebersole
@ -66,9 +66,7 @@ public class CurrentTimestampAnnotationTests {
waitALittle();
// lastly, make sure we can load it..
final AuditedEntity loaded = scope.fromTransaction( (session) -> {
return session.get( AuditedEntity.class, 1 );
} );
final AuditedEntity loaded = scope.fromTransaction( (session) -> session.get( AuditedEntity.class, 1 ) );
assertThat( loaded ).isNotNull();
assertThat( loaded.createdAt ).isEqualTo( merged.createdAt );
@ -86,7 +84,7 @@ public class CurrentTimestampAnnotationTests {
@CurrentTimestamp(event = INSERT)
public Instant createdAt;
@CurrentTimestamp(event = INSERT_OR_UPDATE)
@CurrentTimestamp(event = {INSERT, UPDATE})
public Instant lastUpdatedAt;
//end::mapping-generated-CurrentTimestamp-ex1[]

View File

@ -11,6 +11,7 @@ import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.EnumSet;
import java.util.UUID;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
@ -19,6 +20,7 @@ import jakarta.persistence.Table;
import org.hibernate.annotations.ValueGenerationType;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.generator.InMemoryGenerator;
@ -84,20 +86,15 @@ public class GeneratedUuidTests {
//tag::mapping-generated-custom-ex3[]
public static class UuidValueGeneration implements InMemoryGenerator {
private final GenerationTiming timing;
private final EnumSet<EventType> eventTypes;
public UuidValueGeneration(GeneratedUuidValue annotation) {
timing = annotation.timing();
eventTypes = annotation.timing().getEquivalent().eventTypes();
}
@Override
public boolean generatedOnInsert() {
return timing.includesInsert();
}
@Override
public boolean generatedOnUpdate() {
return timing.includesUpdate();
public EnumSet<EventType> getEventTypes() {
return eventTypes;
}
@Override

View File

@ -123,7 +123,7 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
final GeneratorCreator generation = property.getValueGeneratorCreator();
if ( generation instanceof GeneratedGeneration) {
final GeneratedGeneration valueGeneration = (GeneratedGeneration) generation;
if ( valueGeneration.generatedOnInsert() ) {
if ( valueGeneration.generatesOnInsert() ) {
return true;
}
}
@ -189,7 +189,6 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
}
}
@SuppressWarnings("unchecked")
private void addJoins(
PersistentClass persistentClass,
CompositeMapperBuilder currentMapper,