Skip to content

Commit 5125456

Browse files
committed
HHH-18815 add Generator.allowMutation()
Signed-off-by: Gavin King <[email protected]>
1 parent 731a5db commit 5125456

File tree

4 files changed

+49
-20
lines changed

4 files changed

+49
-20
lines changed

hibernate-core/src/main/java/org/hibernate/annotations/Generated.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,12 @@
9797
/**
9898
* Determines if the value currently assigned to the annotated property
9999
* is included in SQL {@code insert} and {@code update} statements. This
100-
* is useful if the generated value is obtained by transforming the
101-
* assigned property value as it is being written.
100+
* is useful if:
101+
* <ul>
102+
* <li>the generated value is obtained by transforming the assigned
103+
* property value as it is being written, or
104+
* <li>assigning a value disables generation of a value.
105+
* </ul>
102106
* <p>
103107
* Often used in combination with {@link SQLInsert}, {@link SQLUpdate},
104108
* or {@link ColumnTransformer#write()}.

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,13 @@ public interface Generator extends Serializable {
107107
* @param session The session from which the request originates.
108108
*
109109
* @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.
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.
112112
*
113113
* @see #generatedOnExecution()
114114
* @see BeforeExecutionGenerator
115115
* @see OnExecutionGenerator
116+
*
116117
* @since 6.4
117118
*/
118119
default boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
@@ -143,6 +144,19 @@ default boolean allowAssignedIdentifiers() {
143144
return false;
144145
}
145146

147+
/**
148+
* Determine if this generator allows generated fields to be manually assigned a value on
149+
* {@linkplain #getEventTypes events} which do <em>not</em> trigger value generation.
150+
*
151+
* @return {@code true} if this generator allows manually assigned values,
152+
* {@code false} otherwise (default).
153+
*
154+
* @since 7.0
155+
*/
156+
default boolean allowMutation() {
157+
return false;
158+
}
159+
146160
default boolean generatesSometimes() {
147161
return !getEventTypes().isEmpty();
148162
}

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.generator.internal;
66

7+
import org.hibernate.AnnotationException;
78
import org.hibernate.annotations.Generated;
89
import org.hibernate.dialect.Dialect;
910
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -41,7 +42,10 @@ public GeneratedGeneration(EnumSet<EventType> eventTypes) {
4142
public GeneratedGeneration(Generated annotation) {
4243
eventTypes = fromArray( annotation.event() );
4344
sql = isEmpty( annotation.sql() ) ? null : new String[] { annotation.sql() };
44-
writable = annotation.writable() || sql != null;
45+
writable = annotation.writable();
46+
if ( sql != null && writable ) {
47+
throw new AnnotationException( "A field marked '@Generated(writable=true)' may not specify explicit 'sql'" );
48+
}
4549
}
4650

4751
@Override
@@ -51,7 +55,9 @@ public EnumSet<EventType> getEventTypes() {
5155

5256
@Override
5357
public boolean referenceColumnsInSql(Dialect dialect) {
54-
return writable;
58+
// include the column in when the field is writable,
59+
// or when there is an explicit SQL expression
60+
return writable || sql != null;
5561
}
5662

5763
@Override
@@ -61,7 +67,9 @@ public String[] getReferencedColumnValues(Dialect dialect) {
6167

6268
@Override
6369
public boolean writePropertyValue() {
64-
return writable && sql==null;
70+
// include a ? parameter when the field is writable,
71+
// but there is no explicit SQL expression
72+
return writable;
6573
}
6674

6775
@Override
@@ -71,13 +79,15 @@ public boolean generatedOnExecution() {
7179

7280
@Override
7381
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
74-
if ( !writable ) {
82+
if ( writable ) {
83+
// When this is the identifier generator and writable is true, allow pre-assigned identifiers
84+
final EntityPersister entityPersister = session.getEntityPersister( null, entity );
85+
return entityPersister.getGenerator() != this
86+
|| entityPersister.getIdentifier( entity, session ) == null;
87+
}
88+
else {
7589
return true;
7690
}
77-
78-
// When this is the identifier generator and writable is true, allow pre-assigned identifiers
79-
final EntityPersister entityPersister = session.getEntityPersister( null, entity );
80-
return entityPersister.getGenerator() != this || entityPersister.getIdentifier( entity, session ) == null;
8191
}
8292

8393
@Override
@@ -91,4 +101,10 @@ public Object generate(SharedSessionContractImplementor session, Object owner, O
91101
public boolean allowAssignedIdentifiers() {
92102
return writable;
93103
}
104+
105+
@Override
106+
public boolean allowMutation() {
107+
// the user may specify @Immutable if mutation should be disallowed
108+
return true;
109+
}
94110
}

hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,12 @@ public EntityMetamodel(
321321
}
322322
else {
323323
generators[i] = generator;
324-
final boolean noParameter = generatedWithNoParameter( generator );
325-
if ( noParameter && !generator.allowAssignedIdentifiers() ) {
324+
if ( !generator.allowMutation() ) {
326325
propertyInsertability[i] = false;
327326
propertyUpdateability[i] = false;
328327
}
329328
if ( generator.generatesOnInsert() ) {
330-
if ( noParameter ) {
331-
propertyInsertability[i] = false;
332-
}
329+
propertyInsertability[i] = !generatedWithNoParameter( generator );
333330
if ( generator.generatedOnExecution() ) {
334331
foundPostInsertGeneratedValues = true;
335332
if ( generator instanceof BeforeExecutionGenerator ) {
@@ -341,9 +338,7 @@ public EntityMetamodel(
341338
}
342339
}
343340
if ( generator.generatesOnUpdate() ) {
344-
if ( noParameter ) {
345-
propertyInsertability[i] = false;
346-
}
341+
propertyUpdateability[i] = !generatedWithNoParameter( generator );
347342
if ( generator.generatedOnExecution() ) {
348343
foundPostUpdateGeneratedValues = true;
349344
if ( generator instanceof BeforeExecutionGenerator ) {

0 commit comments

Comments
 (0)