Skip to content

Commit 94349ce

Browse files
committed
HHH-19584 add @CurrentTimestamp(allowMutation)
1 parent 68c8712 commit 94349ce

File tree

3 files changed

+52
-15
lines changed

3 files changed

+52
-15
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,17 @@
8585
* this additional {@code select} never occurs.
8686
*/
8787
SourceType source() default SourceType.DB;
88+
89+
/**
90+
* Specifies whether the value may be mutated by the application program
91+
* during {@linkplain #event events} which do <em>not</em> trigger value
92+
* generation.
93+
* <p>
94+
* For example, a field annotated
95+
* {@code CurrentTimestamp(event=INSERT, allowMutation=true)}
96+
* is generated when a record is inserted and may be manually mutated later.
97+
*
98+
* @since 7.1
99+
*/
100+
boolean allowMutation() default false;
88101
}

hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/CurrentTimestampAnnotation.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
public class CurrentTimestampAnnotation implements CurrentTimestamp {
1919
private org.hibernate.generator.EventType[] event;
2020
private org.hibernate.annotations.SourceType source;
21+
private boolean allowMutation;
2122

2223
/**
2324
* Used in creating dynamic annotation instances (e.g. from XML)
2425
*/
2526
public CurrentTimestampAnnotation(ModelsContext modelContext) {
2627
this.event = new org.hibernate.generator.EventType[] {INSERT, UPDATE};
2728
this.source = org.hibernate.annotations.SourceType.DB;
29+
this.allowMutation = false;
2830
}
2931

3032
/**
@@ -33,6 +35,7 @@ public CurrentTimestampAnnotation(ModelsContext modelContext) {
3335
public CurrentTimestampAnnotation(CurrentTimestamp annotation, ModelsContext modelContext) {
3436
this.event = annotation.event();
3537
this.source = annotation.source();
38+
this.allowMutation = annotation.allowMutation();
3639
}
3740

3841
/**
@@ -41,6 +44,7 @@ public CurrentTimestampAnnotation(CurrentTimestamp annotation, ModelsContext mod
4144
public CurrentTimestampAnnotation(Map<String, Object> attributeValues, ModelsContext modelContext) {
4245
this.event = (org.hibernate.generator.EventType[]) attributeValues.get( "event" );
4346
this.source = (org.hibernate.annotations.SourceType) attributeValues.get( "source" );
47+
this.allowMutation = (Boolean) attributeValues.get( "allowMutation" );
4448
}
4549

4650
@Override
@@ -66,5 +70,12 @@ public void source(org.hibernate.annotations.SourceType value) {
6670
this.source = value;
6771
}
6872

73+
@Override
74+
public boolean allowMutation() {
75+
return allowMutation;
76+
}
6977

78+
public void allowMutation(boolean value) {
79+
this.allowMutation = value;
80+
}
7081
}

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
7979
public static final String CLOCK_SETTING_NAME = "hibernate.testing.clock";
8080

8181
private final EnumSet<EventType> eventTypes;
82+
private final boolean allowMutation;
8283

8384
private final CurrentTimestampGeneratorDelegate delegate;
8485
private static final Map<Class<?>, BiFunction<@Nullable Clock, Integer, CurrentTimestampGeneratorDelegate>> GENERATOR_PRODUCERS = new HashMap<>();
@@ -185,16 +186,19 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
185186
public CurrentTimestampGeneration(CurrentTimestamp annotation, Member member, GeneratorCreationContext context) {
186187
delegate = getGeneratorDelegate( annotation.source(), member, context );
187188
eventTypes = fromArray( annotation.event() );
189+
allowMutation = annotation.allowMutation();
188190
}
189191

190192
public CurrentTimestampGeneration(CreationTimestamp annotation, Member member, GeneratorCreationContext context) {
191193
delegate = getGeneratorDelegate( annotation.source(), member, context );
192194
eventTypes = INSERT_ONLY;
195+
allowMutation = false;
193196
}
194197

195198
public CurrentTimestampGeneration(UpdateTimestamp annotation, Member member, GeneratorCreationContext context) {
196199
delegate = getGeneratorDelegate( annotation.source(), member, context );
197200
eventTypes = INSERT_AND_UPDATE;
201+
allowMutation = false;
198202
}
199203

200204
private static CurrentTimestampGeneratorDelegate getGeneratorDelegate(
@@ -216,24 +220,27 @@ static CurrentTimestampGeneratorDelegate getGeneratorDelegate(
216220
context.getDatabase().getDialect(),
217221
basicValue.getMetadata()
218222
);
219-
final Clock baseClock = context.getServiceRegistry()
220-
.requireService( ConfigurationService.class )
221-
.getSetting( CLOCK_SETTING_NAME, value -> (Clock) value );
222-
final Key key = new Key( propertyType, baseClock, size.getPrecision() == null ? 0 : size.getPrecision() );
223-
final CurrentTimestampGeneratorDelegate delegate = GENERATOR_DELEGATES.get( key );
223+
final Clock baseClock =
224+
context.getServiceRegistry().requireService( ConfigurationService.class )
225+
.getSetting( CLOCK_SETTING_NAME, value -> (Clock) value );
226+
final Key key =
227+
new Key( propertyType, baseClock,
228+
size.getPrecision() == null ? 0 : size.getPrecision() );
229+
final var delegate = GENERATOR_DELEGATES.get( key );
224230
if ( delegate != null ) {
225231
return delegate;
226232
}
227-
final BiFunction<@Nullable Clock, Integer, CurrentTimestampGeneratorDelegate> producer = GENERATOR_PRODUCERS.get( key.clazz );
228-
if ( producer == null ) {
229-
return null;
233+
else {
234+
final var producer = GENERATOR_PRODUCERS.get( key.clazz );
235+
if ( producer == null ) {
236+
return null;
237+
}
238+
else {
239+
final var generatorDelegate = producer.apply( key.clock, key.precision );
240+
final var old = GENERATOR_DELEGATES.putIfAbsent( key, generatorDelegate );
241+
return old != null ? old : generatorDelegate;
242+
}
230243
}
231-
final CurrentTimestampGeneratorDelegate generatorDelegate = producer.apply( key.clock, key.precision );
232-
final CurrentTimestampGeneratorDelegate old = GENERATOR_DELEGATES.putIfAbsent(
233-
key,
234-
generatorDelegate
235-
);
236-
return old != null ? old : generatorDelegate;
237244
case DB:
238245
return null;
239246
default:
@@ -255,6 +262,11 @@ public EnumSet<EventType> getEventTypes() {
255262
return eventTypes;
256263
}
257264

265+
@Override
266+
public boolean allowMutation() {
267+
return allowMutation;
268+
}
269+
258270
@Override
259271
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
260272
return delegate.generate();
@@ -276,7 +288,8 @@ public String[] getReferencedColumnValues(Dialect dialect) {
276288
}
277289

278290
interface CurrentTimestampGeneratorDelegate {
279-
// Left out the Generator params, they're not used anyway. Since this is purely internal, this can be changed if needed
291+
// Left out the Generator params, they're not used anyway.
292+
// Since this is purely internal, this can be changed if needed
280293
Object generate();
281294
}
282295

0 commit comments

Comments
 (0)