HHH-18815 introduce Generator.generatedBeforeExecution()
so that GeneratedGeneration does not need to implement BeforeExecutionGenerator Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
5fca1206b2
commit
cf0ab77cf2
|
@ -103,6 +103,7 @@ public abstract class AbstractSaveEventListener<C> implements CallbackRegistryCo
|
|||
final EntityPersister persister = source.getEntityPersister( entityName, entity );
|
||||
final Generator generator = persister.getGenerator();
|
||||
final boolean generatedOnExecution = generator.generatedOnExecution( entity, source );
|
||||
final boolean generatedBeforeExecution = generator.generatedBeforeExecution( entity, source );
|
||||
final Object generatedId;
|
||||
if ( generatedOnExecution ) {
|
||||
// the id gets generated by the database
|
||||
|
@ -114,7 +115,7 @@ public abstract class AbstractSaveEventListener<C> implements CallbackRegistryCo
|
|||
// the @PrePersist callback to happen first
|
||||
generatedId = null;
|
||||
}
|
||||
else {
|
||||
else if ( generatedBeforeExecution ) {
|
||||
// go ahead and generate id, and then set it to
|
||||
// the entity instance, so it will be available
|
||||
// to the entity in the @PrePersist callback
|
||||
|
@ -124,6 +125,11 @@ public abstract class AbstractSaveEventListener<C> implements CallbackRegistryCo
|
|||
}
|
||||
persister.setIdentifier( entity, generatedId, source );
|
||||
}
|
||||
else {
|
||||
// the generator is refusing to generate anything
|
||||
// so use the identifier currently assigned
|
||||
generatedId = persister.getIdentifier( entity, source );
|
||||
}
|
||||
final boolean delayIdentityInserts =
|
||||
!source.isTransactionInProgress()
|
||||
&& !requiresImmediateIdAccess
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.hibernate.generator;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
|
@ -29,6 +30,16 @@ public class Assigned implements Generator {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAssignedIdentifiers() {
|
||||
return true;
|
||||
|
|
|
@ -32,9 +32,10 @@ import static org.hibernate.generator.EventType.UPDATE;
|
|||
* SQL {@code select}, though in certain cases this additional round trip may be avoided.
|
||||
* An important example is id generation using an identity column.
|
||||
* </ul>
|
||||
* A Generator may implement both interfaces and determine the timing of ID generation at runtime.
|
||||
* Furthermore, this condition can be based on the state of the owner entity, see
|
||||
* {@link #generatedOnExecution(Object, SharedSessionContractImplementor) generatedOnExecution}.
|
||||
* A {@code Generator} may implement both interfaces and determine the timing of identifier
|
||||
* generation at runtime. Furthermore, this condition can be based on the state of the owner entity,
|
||||
* see {@link #generatedOnExecution(Object, SharedSessionContractImplementor) generatedOnExecution} and
|
||||
* {@link #generatedBeforeExecution(Object, SharedSessionContractImplementor) generatedBeforeExecution}.
|
||||
* <p>
|
||||
* Generically, a generator may be integrated with the program using the meta-annotation
|
||||
* {@link org.hibernate.annotations.ValueGenerationType}, which associates the generator with
|
||||
|
@ -95,20 +96,16 @@ public interface Generator extends Serializable {
|
|||
boolean generatedOnExecution();
|
||||
|
||||
/**
|
||||
* Determines if the property value is generated when a row is written to the database,
|
||||
* or in Java code that executes before the row is written.
|
||||
* Determines if the property value is generated when a row is written to the database.
|
||||
* <p>
|
||||
* Defaults to {@link #generatedOnExecution()}, but can be overloaded allowing conditional
|
||||
* value generation timing (on/before execution) based on the current state of the owner entity.
|
||||
* Note that a generator <b>must</b> implement both {@link BeforeExecutionGenerator} and
|
||||
* {@link OnExecutionGenerator} to achieve this behavior.
|
||||
* Defaults to {@link #generatedOnExecution()}, but may be overridden to allow conditional
|
||||
* on-execution value generation based on the current state of the owner entity.
|
||||
*
|
||||
* @param entity The instance of the entity owning the attribute for which we are generating a value.
|
||||
* @param session The session from which the request originates.
|
||||
*
|
||||
* @return {@code true} if the value is generated by the database as a side effect of
|
||||
* the execution of an {@code insert} or {@code update} statement, or false if
|
||||
* it is generated in Java code before the statement is executed via JDBC.
|
||||
* the execution of an {@code insert} or {@code update} statement.
|
||||
*
|
||||
* @see #generatedOnExecution()
|
||||
* @see BeforeExecutionGenerator
|
||||
|
@ -120,6 +117,30 @@ public interface Generator extends Serializable {
|
|||
return generatedOnExecution();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the property value is generated before in Java code that executes before
|
||||
* the row is written.
|
||||
* <p>
|
||||
* Defaults to {@link #generatedOnExecution() !generatedOnExecution()}, but may be overridden
|
||||
* to allow conditional before-execution value generation based on the current state of the
|
||||
* owner entity.
|
||||
*
|
||||
* @param entity The instance of the entity owning the attribute for which we are generating a value.
|
||||
* @param session The session from which the request originates.
|
||||
*
|
||||
* @return {@code true} if the value is generated in Java code before the statement is
|
||||
* executed via JDBC.
|
||||
*
|
||||
* @see #generatedOnExecution()
|
||||
* @see BeforeExecutionGenerator
|
||||
* @see OnExecutionGenerator
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
default boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return !generatedOnExecution();
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@linkplain EventType event types} for which this generator should be called
|
||||
* to produce a new value.
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.hibernate.AnnotationException;
|
|||
import org.hibernate.annotations.Generated;
|
||||
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.OnExecutionGenerator;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
@ -27,7 +26,7 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
|
|||
* @author Steve Ebersole
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public class GeneratedGeneration implements OnExecutionGenerator, BeforeExecutionGenerator {
|
||||
public class GeneratedGeneration implements OnExecutionGenerator {
|
||||
|
||||
private final EnumSet<EventType> eventTypes;
|
||||
private final boolean writable;
|
||||
|
@ -72,11 +71,6 @@ public class GeneratedGeneration implements OnExecutionGenerator, BeforeExecutio
|
|||
return writable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
if ( writable ) {
|
||||
|
@ -90,13 +84,6 @@ public class GeneratedGeneration implements OnExecutionGenerator, BeforeExecutio
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
final EntityPersister entityPersister = session.getEntityPersister( null, owner );
|
||||
assert entityPersister.getGenerator() == this;
|
||||
return entityPersister.getIdentifier( owner, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAssignedIdentifiers() {
|
||||
return writable;
|
||||
|
|
|
@ -146,32 +146,47 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
}
|
||||
}
|
||||
final Generator generator = persister.getGenerator();
|
||||
if ( !generator.generatedOnExecution( entity, this ) ) {
|
||||
if ( generator.generatesOnInsert() ) {
|
||||
id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
|
||||
if ( generator.generatedBeforeExecution( entity, this ) ) {
|
||||
if ( !generator.generatesOnInsert() ) {
|
||||
throw new IdentifierGenerationException( "Identifier generator must generate on insert" );
|
||||
}
|
||||
id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
|
||||
if ( firePreInsert(entity, id, state, persister) ) {
|
||||
return id;
|
||||
}
|
||||
else {
|
||||
id = persister.getIdentifier( entity, this );
|
||||
if ( id == null ) {
|
||||
throw new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'insert()'" );
|
||||
}
|
||||
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
persister.getInsertCoordinator().insert( entity, id, state, this );
|
||||
persister.setIdentifier( entity, id, this );
|
||||
}
|
||||
}
|
||||
else if ( generator.generatedOnExecution( entity, this ) ) {
|
||||
if ( !generator.generatesOnInsert() ) {
|
||||
throw new IdentifierGenerationException( "Identifier generator must generate on insert" );
|
||||
}
|
||||
if ( firePreInsert(entity, null, state, persister) ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
getInterceptor().onInsert( entity, null, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
|
||||
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
|
||||
persister.setIdentifier( entity, id, this );
|
||||
}
|
||||
}
|
||||
else { // assigned identifier
|
||||
id = persister.getIdentifier( entity, this );
|
||||
if ( id == null ) {
|
||||
throw new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'insert()'" );
|
||||
}
|
||||
if ( firePreInsert(entity, id, state, persister) ) {
|
||||
return id;
|
||||
}
|
||||
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
persister.getInsertCoordinator().insert( entity, id, state, this );
|
||||
}
|
||||
else {
|
||||
if ( firePreInsert(entity, null, state, persister) ) {
|
||||
return null;
|
||||
else {
|
||||
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
persister.getInsertCoordinator().insert( entity, id, state, this );
|
||||
}
|
||||
getInterceptor()
|
||||
.onInsert( entity, null, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
|
||||
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
|
||||
}
|
||||
persister.setIdentifier( entity, id, this );
|
||||
forEachOwnedCollection( entity, id, persister,
|
||||
(descriptor, collection) -> {
|
||||
descriptor.recreate( collection, id, this);
|
||||
|
|
|
@ -776,7 +776,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
|
||||
@Override
|
||||
public Object execute(SharedSessionContractImplementor session, Object incomingObject) {
|
||||
if ( !generator.generatedOnExecution( incomingObject, session ) ) {
|
||||
if ( generator.generatedBeforeExecution( incomingObject, session ) ) {
|
||||
return generator.generate( session, incomingObject, null, INSERT );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -140,7 +140,7 @@ public class InsertCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& generator.generatesOnInsert()
|
||||
&& !generator.generatedOnExecution( entity, session ) ) {
|
||||
&& generator.generatedBeforeExecution( entity, session ) ) {
|
||||
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT );
|
||||
persister.setPropertyValue( entity, i, values[i] );
|
||||
foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution();
|
||||
|
@ -407,7 +407,7 @@ public class InsertCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
else {
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerated( generator ) ) {
|
||||
if ( session != null && !generator.generatedOnExecution( object, session ) ) {
|
||||
if ( session != null && generator.generatedBeforeExecution( object, session ) ) {
|
||||
attributeInclusions[attributeIndex] = true;
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
|
|
|
@ -540,7 +540,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& generator.generatesOnUpdate()
|
||||
&& !generator.generatedOnExecution( object, session ) ) {
|
||||
&& generator.generatedBeforeExecution( object, session ) ) {
|
||||
newValues[i] = ( (BeforeExecutionGenerator) generator ).generate( session, object, newValues[i], UPDATE );
|
||||
entityPersister().setPropertyValue( object, i, newValues[i] );
|
||||
fieldsPreUpdateNeeded[count++] = i;
|
||||
|
@ -667,7 +667,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
final boolean generated = isValueGenerated( generator );
|
||||
final boolean needsDynamicUpdate = generated && session != null && !generator.generatedOnExecution( entity, session );
|
||||
final boolean needsDynamicUpdate =
|
||||
generated && session != null && generator.generatedBeforeExecution( entity, session );
|
||||
final boolean generatedInSql = generated && isValueGenerationInSql( generator, dialect );
|
||||
if ( generatedInSql && !needsDynamicUpdate && !( (OnExecutionGenerator) generator ).writePropertyValue() ) {
|
||||
analysis.registerValueGeneratedInSqlNoWrite();
|
||||
|
|
|
@ -306,8 +306,13 @@ public class MixedTimingGeneratorsTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution(Object owner, SharedSessionContractImplementor session) {
|
||||
return !( (RandomEntity) owner ).getName().contains( "random" );
|
||||
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return !generatedBeforeExecution( entity, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return ( (RandomEntity) entity ).getName().contains( "random" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,8 +338,13 @@ public class MixedTimingGeneratorsTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecution(Object owner, SharedSessionContractImplementor session) {
|
||||
return !( (StringGeneratedEntity) owner ).getName().contains( "generated" );
|
||||
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return !generatedBeforeExecution( entity, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
|
||||
return ( (StringGeneratedEntity) entity ).getName().contains( "generated" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue