Skip to content

Commit cf0ab77

Browse files
committed
HHH-18815 introduce Generator.generatedBeforeExecution()
so that GeneratedGeneration does not need to implement BeforeExecutionGenerator Signed-off-by: Gavin King <[email protected]>
1 parent 5fca120 commit cf0ab77

File tree

9 files changed

+103
-52
lines changed

9 files changed

+103
-52
lines changed

hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ protected Object saveWithGeneratedId(
103103
final EntityPersister persister = source.getEntityPersister( entityName, entity );
104104
final Generator generator = persister.getGenerator();
105105
final boolean generatedOnExecution = generator.generatedOnExecution( entity, source );
106+
final boolean generatedBeforeExecution = generator.generatedBeforeExecution( entity, source );
106107
final Object generatedId;
107108
if ( generatedOnExecution ) {
108109
// the id gets generated by the database
@@ -114,7 +115,7 @@ else if ( !generator.generatesOnInsert() ) {
114115
// the @PrePersist callback to happen first
115116
generatedId = null;
116117
}
117-
else {
118+
else if ( generatedBeforeExecution ) {
118119
// go ahead and generate id, and then set it to
119120
// the entity instance, so it will be available
120121
// to the entity in the @PrePersist callback
@@ -124,6 +125,11 @@ else if ( !generator.generatesOnInsert() ) {
124125
}
125126
persister.setIdentifier( entity, generatedId, source );
126127
}
128+
else {
129+
// the generator is refusing to generate anything
130+
// so use the identifier currently assigned
131+
generatedId = persister.getIdentifier( entity, source );
132+
}
127133
final boolean delayIdentityInserts =
128134
!source.isTransactionInProgress()
129135
&& !requiresImmediateIdAccess

hibernate-core/src/main/java/org/hibernate/generator/Assigned.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.generator;
66

77
import org.hibernate.Internal;
8+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
89

910
import java.util.EnumSet;
1011

@@ -29,6 +30,16 @@ public boolean generatedOnExecution() {
2930
return false;
3031
}
3132

33+
@Override
34+
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
35+
return false;
36+
}
37+
38+
@Override
39+
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
40+
return false;
41+
}
42+
3243
@Override
3344
public boolean allowAssignedIdentifiers() {
3445
return true;

hibernate-core/src/main/java/org/hibernate/generator/Generator.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
* SQL {@code select}, though in certain cases this additional round trip may be avoided.
3333
* An important example is id generation using an identity column.
3434
* </ul>
35-
* A Generator may implement both interfaces and determine the timing of ID generation at runtime.
36-
* Furthermore, this condition can be based on the state of the owner entity, see
37-
* {@link #generatedOnExecution(Object, SharedSessionContractImplementor) generatedOnExecution}.
35+
* A {@code Generator} may implement both interfaces and determine the timing of identifier
36+
* generation at runtime. Furthermore, this condition can be based on the state of the owner entity,
37+
* see {@link #generatedOnExecution(Object, SharedSessionContractImplementor) generatedOnExecution} and
38+
* {@link #generatedBeforeExecution(Object, SharedSessionContractImplementor) generatedBeforeExecution}.
3839
* <p>
3940
* Generically, a generator may be integrated with the program using the meta-annotation
4041
* {@link org.hibernate.annotations.ValueGenerationType}, which associates the generator with
@@ -95,20 +96,16 @@ public interface Generator extends Serializable {
9596
boolean generatedOnExecution();
9697

9798
/**
98-
* Determines if the property value is generated when a row is written to the database,
99-
* or in Java code that executes before the row is written.
99+
* Determines if the property value is generated when a row is written to the database.
100100
* <p>
101-
* Defaults to {@link #generatedOnExecution()}, but can be overloaded allowing conditional
102-
* value generation timing (on/before execution) based on the current state of the owner entity.
103-
* Note that a generator <b>must</b> implement both {@link BeforeExecutionGenerator} and
104-
* {@link OnExecutionGenerator} to achieve this behavior.
101+
* Defaults to {@link #generatedOnExecution()}, but may be overridden to allow conditional
102+
* on-execution value generation based on the current state of the owner entity.
105103
*
106104
* @param entity The instance of the entity owning the attribute for which we are generating a value.
107105
* @param session The session from which the request originates.
108106
*
109107
* @return {@code true} if the value is generated by the database as a side effect of
110-
* the execution of an {@code insert} or {@code update} statement, or false if
111-
* it is generated in Java code before the statement is executed via JDBC.
108+
* the execution of an {@code insert} or {@code update} statement.
112109
*
113110
* @see #generatedOnExecution()
114111
* @see BeforeExecutionGenerator
@@ -120,6 +117,30 @@ default boolean generatedOnExecution(Object entity, SharedSessionContractImpleme
120117
return generatedOnExecution();
121118
}
122119

120+
/**
121+
* Determines if the property value is generated before in Java code that executes before
122+
* the row is written.
123+
* <p>
124+
* Defaults to {@link #generatedOnExecution() !generatedOnExecution()}, but may be overridden
125+
* to allow conditional before-execution value generation based on the current state of the
126+
* owner entity.
127+
*
128+
* @param entity The instance of the entity owning the attribute for which we are generating a value.
129+
* @param session The session from which the request originates.
130+
*
131+
* @return {@code true} if the value is generated in Java code before the statement is
132+
* executed via JDBC.
133+
*
134+
* @see #generatedOnExecution()
135+
* @see BeforeExecutionGenerator
136+
* @see OnExecutionGenerator
137+
*
138+
* @since 7.0
139+
*/
140+
default boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
141+
return !generatedOnExecution();
142+
}
143+
123144
/**
124145
* The {@linkplain EventType event types} for which this generator should be called
125146
* to produce a new value.

hibernate-core/src/main/java/org/hibernate/generator/internal/GeneratedGeneration.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import org.hibernate.annotations.Generated;
99
import org.hibernate.dialect.Dialect;
1010
import org.hibernate.engine.spi.SharedSessionContractImplementor;
11-
import org.hibernate.generator.BeforeExecutionGenerator;
1211
import org.hibernate.generator.EventType;
1312
import org.hibernate.generator.OnExecutionGenerator;
1413
import org.hibernate.persister.entity.EntityPersister;
@@ -27,7 +26,7 @@
2726
* @author Steve Ebersole
2827
* @author Gunnar Morling
2928
*/
30-
public class GeneratedGeneration implements OnExecutionGenerator, BeforeExecutionGenerator {
29+
public class GeneratedGeneration implements OnExecutionGenerator {
3130

3231
private final EnumSet<EventType> eventTypes;
3332
private final boolean writable;
@@ -72,11 +71,6 @@ public boolean writePropertyValue() {
7271
return writable;
7372
}
7473

75-
@Override
76-
public boolean generatedOnExecution() {
77-
return true;
78-
}
79-
8074
@Override
8175
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
8276
if ( writable ) {
@@ -90,13 +84,6 @@ public boolean generatedOnExecution(Object entity, SharedSessionContractImplemen
9084
}
9185
}
9286

93-
@Override
94-
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
95-
final EntityPersister entityPersister = session.getEntityPersister( null, owner );
96-
assert entityPersister.getGenerator() == this;
97-
return entityPersister.getIdentifier( owner, session );
98-
}
99-
10087
@Override
10188
public boolean allowAssignedIdentifiers() {
10289
return writable;

hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -146,32 +146,47 @@ public Object insert(String entityName, Object entity) {
146146
}
147147
}
148148
final Generator generator = persister.getGenerator();
149-
if ( !generator.generatedOnExecution( entity, this ) ) {
150-
if ( generator.generatesOnInsert() ) {
151-
id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
152-
}
153-
else {
154-
id = persister.getIdentifier( entity, this );
155-
if ( id == null ) {
156-
throw new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'insert()'" );
157-
}
149+
if ( generator.generatedBeforeExecution( entity, this ) ) {
150+
if ( !generator.generatesOnInsert() ) {
151+
throw new IdentifierGenerationException( "Identifier generator must generate on insert" );
158152
}
153+
id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
159154
if ( firePreInsert(entity, id, state, persister) ) {
160155
return id;
161156
}
162-
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
163-
persister.getInsertCoordinator().insert( entity, id, state, this );
157+
else {
158+
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
159+
persister.getInsertCoordinator().insert( entity, id, state, this );
160+
persister.setIdentifier( entity, id, this );
161+
}
164162
}
165-
else {
163+
else if ( generator.generatedOnExecution( entity, this ) ) {
164+
if ( !generator.generatesOnInsert() ) {
165+
throw new IdentifierGenerationException( "Identifier generator must generate on insert" );
166+
}
166167
if ( firePreInsert(entity, null, state, persister) ) {
167168
return null;
168169
}
169-
getInterceptor()
170-
.onInsert( entity, null, state, persister.getPropertyNames(), persister.getPropertyTypes() );
171-
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
172-
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
170+
else {
171+
getInterceptor().onInsert( entity, null, state, persister.getPropertyNames(), persister.getPropertyTypes() );
172+
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
173+
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
174+
persister.setIdentifier( entity, id, this );
175+
}
176+
}
177+
else { // assigned identifier
178+
id = persister.getIdentifier( entity, this );
179+
if ( id == null ) {
180+
throw new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'insert()'" );
181+
}
182+
if ( firePreInsert(entity, id, state, persister) ) {
183+
return id;
184+
}
185+
else {
186+
getInterceptor().onInsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
187+
persister.getInsertCoordinator().insert( entity, id, state, this );
188+
}
173189
}
174-
persister.setIdentifier( entity, id, this );
175190
forEachOwnedCollection( entity, id, persister,
176191
(descriptor, collection) -> {
177192
descriptor.recreate( collection, id, this);

hibernate-core/src/main/java/org/hibernate/mapping/Component.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ public int getPropertyIndex() {
776776

777777
@Override
778778
public Object execute(SharedSessionContractImplementor session, Object incomingObject) {
779-
if ( !generator.generatedOnExecution( incomingObject, session ) ) {
779+
if ( generator.generatedBeforeExecution( incomingObject, session ) ) {
780780
return generator.generate( session, incomingObject, null, INSERT );
781781
}
782782
else {

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ protected boolean preInsertInMemoryValueGeneration(Object[] values, Object entit
140140
final Generator generator = generators[i];
141141
if ( generator != null
142142
&& generator.generatesOnInsert()
143-
&& !generator.generatedOnExecution( entity, session ) ) {
143+
&& generator.generatedBeforeExecution( entity, session ) ) {
144144
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT );
145145
persister.setPropertyValue( entity, i, values[i] );
146146
foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution();
@@ -407,7 +407,7 @@ private void applyTableInsertDetails(
407407
else {
408408
final Generator generator = attributeMapping.getGenerator();
409409
if ( isValueGenerated( generator ) ) {
410-
if ( session != null && !generator.generatedOnExecution( object, session ) ) {
410+
if ( session != null && generator.generatedBeforeExecution( object, session ) ) {
411411
attributeInclusions[attributeIndex] = true;
412412
attributeMapping.forEachInsertable( insertGroupBuilder );
413413
}

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ private int[] preUpdateInMemoryValueGeneration(
540540
final Generator generator = generators[i];
541541
if ( generator != null
542542
&& generator.generatesOnUpdate()
543-
&& !generator.generatedOnExecution( object, session ) ) {
543+
&& generator.generatedBeforeExecution( object, session ) ) {
544544
newValues[i] = ( (BeforeExecutionGenerator) generator ).generate( session, object, newValues[i], UPDATE );
545545
entityPersister().setPropertyValue( object, i, newValues[i] );
546546
fieldsPreUpdateNeeded[count++] = i;
@@ -667,7 +667,8 @@ private void processAttribute(
667667

668668
final Generator generator = attributeMapping.getGenerator();
669669
final boolean generated = isValueGenerated( generator );
670-
final boolean needsDynamicUpdate = generated && session != null && !generator.generatedOnExecution( entity, session );
670+
final boolean needsDynamicUpdate =
671+
generated && session != null && generator.generatedBeforeExecution( entity, session );
671672
final boolean generatedInSql = generated && isValueGenerationInSql( generator, dialect );
672673
if ( generatedInSql && !needsDynamicUpdate && !( (OnExecutionGenerator) generator ).writePropertyValue() ) {
673674
analysis.registerValueGeneratedInSqlNoWrite();

hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/MixedTimingGeneratorsTest.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,13 @@ public boolean generatedOnExecution() {
306306
}
307307

308308
@Override
309-
public boolean generatedOnExecution(Object owner, SharedSessionContractImplementor session) {
310-
return !( (RandomEntity) owner ).getName().contains( "random" );
309+
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
310+
return !generatedBeforeExecution( entity, session );
311+
}
312+
313+
@Override
314+
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
315+
return ( (RandomEntity) entity ).getName().contains( "random" );
311316
}
312317
}
313318

@@ -333,8 +338,13 @@ public boolean generatedOnExecution() {
333338
}
334339

335340
@Override
336-
public boolean generatedOnExecution(Object owner, SharedSessionContractImplementor session) {
337-
return !( (StringGeneratedEntity) owner ).getName().contains( "generated" );
341+
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
342+
return !generatedBeforeExecution( entity, session );
343+
}
344+
345+
@Override
346+
public boolean generatedBeforeExecution(Object entity, SharedSessionContractImplementor session) {
347+
return ( (StringGeneratedEntity) entity ).getName().contains( "generated" );
338348
}
339349

340350
@Override

0 commit comments

Comments
 (0)