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