View Javadoc
1   package pk.lucidxpo.ynami.persistence.model;
2   
3   import jakarta.persistence.Column;
4   import jakarta.persistence.EntityListeners;
5   import jakarta.persistence.Id;
6   import jakarta.persistence.MappedSuperclass;
7   import lombok.Data;
8   import org.hibernate.annotations.CreationTimestamp;
9   import org.hibernate.annotations.UpdateTimestamp;
10  import org.springframework.data.annotation.CreatedBy;
11  import org.springframework.data.annotation.LastModifiedBy;
12  import org.springframework.data.jpa.domain.support.AuditingEntityListener;
13  
14  import java.time.Instant;
15  
16  import static org.hibernate.annotations.SourceType.DB;
17  import static pk.lucidxpo.ynami.utils.Identity.randomID;
18  
19  @Data
20  @MappedSuperclass
21  @EntityListeners({AuditingEntityListener.class})
22  public abstract class Auditable<U> implements Identifiable {
23      //    TODO: consider replacing this class with org.springframework.data.jpa.domain.AbstractAuditable
24      @Id
25      @Column(nullable = false, updatable = false)
26      private String id = randomID();
27  
28      // The @CreatedDate and @CreationTimestamp are convenient annotation which sets the field value to the current
29      // timestamp when the entity is first saved. @CreatedDate is a Spring annotation. It is applicable to all stores
30      // covered by Spring Data: JPA, JDBC, R2DBC, MongoDb, Cassandra and so on, whereas @CreationTimestamp is a Hibernate
31      // annotation. It is applicable to Hibernate only. By default, both of these annotations use the current date of
32      // the Java Virtual Machine when setting property values. Starting from Hibernate 6.0.0, we can optionally specify
33      // the database as the source of the date. However, when using @CreationTimestamp and @UpdateTimestamp, we have to
34      // keep in mind that Hibernate generates new timestamps on a per-field basis. This leads to multiple timestamps
35      // being different, even though they were set by the same INSERT or UPDATE statement. Main reason to use the
36      // @CreationTimestamp instead of @CreatedDate is, Spring Data Jpa sets the creation timestamp with nanoseconds
37      // (9 digits) precision on java object but saves the object with microseconds (6 digits) precision in the database
38      // on linux machines (this issue doesn't happen on MAC) and hence the assertions in the integration tests fail
39      // due to difference in precisions. So, setting 'source = DB' on the @CreationTimestamp annotation helps resolve
40      // this issue and tests work on both Mac and Linux.
41      // Insertable => Whether the column is included in SQL INSERT statements generated by the persistence provider.
42      // Updatable => Whether the column is included in SQL UPDATE statements generated by the persistence provider.
43      @CreationTimestamp(source = DB)
44      @Column(nullable = false, insertable = false, updatable = false)
45      private Instant createdDate;
46  
47      // The @LastModifiedDate and @UpdateTimestamp are convenient annotation which automatically sets the field value to
48      // the current timestamp on each entity update. @LastModifiedDate is a Spring annotation. It is applicable to all
49      // stores covered by Spring Data: JPA, JDBC, R2DBC, MongoDb, Cassandra and so on, whereas @UpdateTimestamp is a
50      // Hibernate annotation. It is applicable to Hibernate only.By default, both of these annotations use the current
51      // date of the Java Virtual Machine when setting property values. Starting from Hibernate 6.0.0, we can optionally
52      // specify the database as the source of the date. Main reason to use the @UpdateTimestamp instead of
53      // @LastModifiedDate is, Spring Data Jpa sets the updation timestamp with nanoseconds (9 digits) precision on java
54      // object but saves the object with microseconds (6 digits) precision in the database on linux machines (this issue
55      // doesn't happen on MAC) and hence the assertions in the integration tests fail due to difference in precisions.
56      // So, setting 'source = DB' on the @UpdateTimestamp annotation helps resolve this issue and tests work on both Mac
57      // and Linux.
58      // Insertable => Whether the column is included in SQL INSERT statements generated by the persistence provider.
59      // Updatable => Whether the column is included in SQL UPDATE statements generated by the persistence provider.
60      @UpdateTimestamp(source = DB)
61      @Column(insertable = false, updatable = false)
62      private Instant lastModifiedDate;
63  
64      //    @ManyToOne
65      @CreatedBy
66      @Column(nullable = false, updatable = false)
67      private U createdBy;
68  
69      @Column(nullable = false)
70  //    @ManyToOne
71      @LastModifiedBy
72      private U lastModifiedBy;
73  }