Skip to content

Commit cc610a1

Browse files
committed
HHH-17325 Add SoftDeleteTimestamp annotation
1 parent aa26709 commit cc610a1

File tree

10 files changed

+367
-10
lines changed

10 files changed

+367
-10
lines changed

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static java.lang.annotation.ElementType.METHOD;
1616
import static java.lang.annotation.RetentionPolicy.RUNTIME;
1717
import static org.hibernate.generator.EventType.INSERT;
18+
import static org.hibernate.generator.EventType.SOFT_DELETE;
1819
import static org.hibernate.generator.EventType.UPDATE;
1920

2021
/**
@@ -59,23 +60,27 @@
5960
*
6061
* @see UpdateTimestamp
6162
* @see CreationTimestamp
63+
* @see SoftDeleteTimestamp
6264
* @see CurrentTimestampGeneration
6365
*
6466
* @since 6.0
6567
*
6668
* @author Steve Ebersole
69+
* @author Yongjun Hong
6770
*/
6871
@ValueGenerationType(generatedBy = CurrentTimestampGeneration.class)
6972
@Retention(RUNTIME)
7073
@Target({ FIELD, METHOD, ANNOTATION_TYPE })
7174
public @interface CurrentTimestamp {
7275
/**
73-
* Determines when the timestamp is generated. But default, it is updated
74-
* when any SQL {@code insert} or {@code update} statement is executed.
75-
* If it should be generated just once, on the initial SQL {@code insert},
76-
* explicitly specify {@link EventType#INSERT event = INSERT}.
76+
* Determines when the timestamp is generated. By default, it is updated
77+
* when any SQL {@code insert}, {@code update}, or soft-delete operation
78+
* is executed. If it should be generated just once, on the initial SQL
79+
* {@code insert}, explicitly specify {@link EventType#INSERT event = INSERT}.
80+
* For soft-delete operations, {@link EventType#SOFT_DELETE} can be used.
7781
*/
78-
EventType[] event() default {INSERT, UPDATE};
82+
EventType[] event() default {INSERT, UPDATE, SOFT_DELETE};
83+
7984

8085
/**
8186
* Specifies how the timestamp is generated. By default, it is generated
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.annotations;
6+
7+
import org.hibernate.generator.internal.CurrentTimestampGeneration;
8+
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.Target;
11+
12+
import static java.lang.annotation.ElementType.FIELD;
13+
import static java.lang.annotation.ElementType.METHOD;
14+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
15+
16+
/**
17+
* Specifies that the annotated field or property is a generated <em>soft delete timestamp</em>.
18+
* The timestamp is generated just once, when an entity instance is soft-deleted in the database.
19+
* <p>
20+
* By default, the timestamp is generated by {@linkplain java.time.Clock#instant in memory}.
21+
* but this may be changed by explicitly specifying the {@link #source}.
22+
* Otherwise, this annotation is a synonym for
23+
* {@link SoftDeleteTimestamp @SoftDeleteTimestamp(source=VM)}.
24+
* <p>
25+
* The annotated property may be of any one of the following types:
26+
* {@link java.util.Date},
27+
* {@link java.util.Calendar},
28+
* {@link java.sql.Date},
29+
* {@link java.sql.Time},
30+
* {@link java.sql.Timestamp},
31+
* {@link java.time.Instant},
32+
* {@link java.time.LocalDate},
33+
* {@link java.time.LocalDateTime},
34+
* {@link java.time.LocalTime},
35+
* {@link java.time.MonthDay},
36+
* {@link java.time.OffsetDateTime},
37+
* {@link java.time.OffsetTime},
38+
* {@link java.time.Year},
39+
* {@link java.time.YearMonth}, or
40+
* {@link java.time.ZonedDateTime}.
41+
* <p>
42+
* A field annotated {@code @SoftDeleteTimeStamp} may not be directly set by the application
43+
* program.
44+
*
45+
* @see SoftDeleteTimestamp
46+
* @see CurrentTimestamp
47+
*
48+
* @author Yongjun Hong
49+
*/
50+
@ValueGenerationType(generatedBy = CurrentTimestampGeneration.class)
51+
@Retention(RUNTIME)
52+
@Target({FIELD, METHOD})
53+
public @interface SoftDeleteTimestamp {
54+
/**
55+
* Specifies how the timestamp is generated. By default, it is generated
56+
* in memory, which might save a round trip to the database, depending on
57+
* the capabilities of the database and JDBC driver.
58+
*/
59+
SourceType source() default SourceType.VM;
60+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* @see CurrentTimestamp#source()
1212
* @see UpdateTimestamp#source()
1313
* @see CreationTimestamp#source()
14+
* @see SoftDeleteTimestamp#source()
1415
* @see Source
1516
*
1617
* @author Hardy Ferentschik

hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* for unused because
2626
*
2727
* @author Steve Ebersole
28+
* @author Yongjun Hong
2829
*/
2930
@SuppressWarnings({ "deprecation", "removal", "unused" })
3031
public interface HibernateAnnotations {
@@ -511,6 +512,10 @@ public interface HibernateAnnotations {
511512
SoftDelete.class,
512513
SoftDeleteAnnotation.class
513514
);
515+
OrmAnnotationDescriptor<SoftDeleteTimestamp,SoftDeleteTimeStampAnnotation> SOFT_DELETE_TIMESTAMP = new OrmAnnotationDescriptor<>(
516+
SoftDeleteTimestamp.class,
517+
SoftDeleteTimeStampAnnotation.class
518+
);
514519
OrmAnnotationDescriptor<SortComparator,SortComparatorAnnotation> SORT_COMPARATOR = new OrmAnnotationDescriptor<>(
515520
SortComparator.class,
516521
SortComparatorAnnotation.class

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.hibernate.models.spi.SourceModelBuildingContext;
1212

1313
import static org.hibernate.generator.EventType.INSERT;
14+
import static org.hibernate.generator.EventType.SOFT_DELETE;
1415
import static org.hibernate.generator.EventType.UPDATE;
1516

1617
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
@@ -23,7 +24,7 @@ public class CurrentTimestampAnnotation implements CurrentTimestamp {
2324
* Used in creating dynamic annotation instances (e.g. from XML)
2425
*/
2526
public CurrentTimestampAnnotation(SourceModelBuildingContext modelContext) {
26-
this.event = new org.hibernate.generator.EventType[] {INSERT, UPDATE};
27+
this.event = new org.hibernate.generator.EventType[] {INSERT, UPDATE, SOFT_DELETE};
2728
this.source = org.hibernate.annotations.SourceType.DB;
2829
}
2930

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.models.annotations.internal;
6+
7+
import org.hibernate.annotations.SoftDeleteTimestamp;
8+
import org.hibernate.annotations.SourceType;
9+
import org.hibernate.models.spi.SourceModelBuildingContext;
10+
11+
import java.lang.annotation.Annotation;
12+
import java.util.Map;
13+
14+
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
15+
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
16+
public class SoftDeleteTimeStampAnnotation implements SoftDeleteTimestamp {
17+
private org.hibernate.annotations.SourceType source;
18+
19+
/**
20+
* Used in creating dynamic annotation instances (e.g. from XML)
21+
*/
22+
public SoftDeleteTimeStampAnnotation(SourceModelBuildingContext modelContext) {
23+
this.source = org.hibernate.annotations.SourceType.VM;
24+
}
25+
26+
/**
27+
* Used in creating annotation instances from JDK variant
28+
*/
29+
public SoftDeleteTimeStampAnnotation(SoftDeleteTimestamp annotation, SourceModelBuildingContext modelContext) {
30+
this.source = annotation.source();
31+
}
32+
33+
/**
34+
* Used in creating annotation instances from Jandex variant
35+
*/
36+
public SoftDeleteTimeStampAnnotation(Map<String, Object> attributeValues, SourceModelBuildingContext modelContext) {
37+
this.source = (org.hibernate.annotations.SourceType) attributeValues.get( "source" );
38+
}
39+
40+
@Override
41+
public Class<? extends Annotation> annotationType() {
42+
return SoftDeleteTimestamp.class;
43+
}
44+
45+
@Override
46+
public SourceType source() {
47+
return source;
48+
}
49+
50+
public void source(org.hibernate.annotations.SourceType value) {
51+
this.source = value;
52+
}
53+
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* even though there are only two types.
1414
*
1515
* @author Gavin King
16+
* @author Yongjun Hong
1617
*
1718
* @since 6.2
1819
*
@@ -35,5 +36,13 @@ public enum EventType {
3536
* This indicates, for example, that a version number should be
3637
* incremented.
3738
*/
38-
UPDATE;
39+
UPDATE,
40+
41+
/**
42+
* An event that occurs when any {@code update} statements needed
43+
* to soft-delete an entity instance are executed.
44+
* This indicates, for example, that a soft-delete flag should be
45+
* set to true or a deletion timestamp should be recorded.
46+
*/
47+
SOFT_DELETE;
3948
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88
import java.util.Set;
99

1010
import static org.hibernate.generator.EventType.INSERT;
11+
import static org.hibernate.generator.EventType.SOFT_DELETE;
1112
import static org.hibernate.generator.EventType.UPDATE;
1213

1314
/**
1415
* For convenience, enumerates the possible combinations of {@link EventType}.
1516
*
1617
* @author Gavin King
18+
* @author Yongjun Hong
1719
*
1820
* @since 6.2
1921
*/
2022
public class EventTypeSets {
2123
public static final EnumSet<EventType> NONE = EnumSet.noneOf(EventType.class);
2224
public static final EnumSet<EventType> INSERT_ONLY = EnumSet.of(INSERT);
2325
public static final EnumSet<EventType> UPDATE_ONLY = EnumSet.of(UPDATE);
26+
public static final EnumSet<EventType> SOFT_DELETE_ONLY = EnumSet.of(SOFT_DELETE);
2427
public static final EnumSet<EventType> INSERT_AND_UPDATE = EnumSet.of(INSERT, UPDATE);
2528
public static final EnumSet<EventType> ALL = EnumSet.allOf(EventType.class);
2629

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.hibernate.SessionFactory;
3131
import org.hibernate.annotations.CreationTimestamp;
3232
import org.hibernate.annotations.CurrentTimestamp;
33+
import org.hibernate.annotations.SoftDeleteTimestamp;
3334
import org.hibernate.annotations.SourceType;
3435
import org.hibernate.annotations.UpdateTimestamp;
3536
import org.hibernate.dialect.Dialect;
@@ -48,30 +49,33 @@
4849

4950
import static org.hibernate.generator.EventTypeSets.INSERT_AND_UPDATE;
5051
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
52+
import static org.hibernate.generator.EventTypeSets.SOFT_DELETE_ONLY;
5153
import static org.hibernate.generator.EventTypeSets.fromArray;
5254

5355
/**
5456
* Value generation strategy which produces a timestamp using the database
5557
* {@link Dialect#currentTimestamp() current_timestamp} function or the JVM
5658
* {@linkplain java.time.Clock#instant() current instant}.
5759
* <p>
58-
* Underlies the {@link CurrentTimestamp}, {@link CreationTimestamp}, and
59-
* {@link UpdateTimestamp} annotations.
60+
* Underlies the {@link CurrentTimestamp}, {@link CreationTimestamp}, {@link UpdateTimestamp}
61+
* and {@link SoftDeleteTimestamp} annotations.
6062
*
6163
* @see CurrentTimestamp
6264
* @see CreationTimestamp
6365
* @see UpdateTimestamp
66+
* @see SoftDeleteTimestamp
6467
*
6568
* @since 6.0
6669
*
6770
* @author Steve Ebersole
6871
* @author Gavin King
72+
* @author Yongjun Hong
6973
*/
7074
public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnExecutionGenerator {
7175

7276
/**
7377
* Configuration property name to set a custom {@link Clock} for Hibernate ORM to use when generating VM based
74-
* timestamp values for e.g. {@link CurrentTimestamp}, {@link CreationTimestamp}, {@link UpdateTimestamp}
78+
* timestamp values for e.g. {@link CurrentTimestamp}, {@link CreationTimestamp}, {@link UpdateTimestamp}, {@link SoftDeleteTimestamp}
7579
* and {@link org.hibernate.type.descriptor.java.VersionJavaType} methods.
7680
*
7781
* @since 6.6
@@ -197,6 +201,11 @@ public CurrentTimestampGeneration(UpdateTimestamp annotation, Member member, Gen
197201
eventTypes = INSERT_AND_UPDATE;
198202
}
199203

204+
public CurrentTimestampGeneration(SoftDeleteTimestamp annotation, Member member, GeneratorCreationContext context) {
205+
delegate = getGeneratorDelegate( annotation.source(), member, context );
206+
eventTypes = SOFT_DELETE_ONLY;
207+
}
208+
200209
private static CurrentTimestampGeneratorDelegate getGeneratorDelegate(
201210
SourceType source,
202211
Member member,

0 commit comments

Comments
 (0)