Enable auditing with Spring Data Jpa's @CreatedDate
and @LastModified
Spring Data Jpa provides auditing feature which includes @CreateDate
, @CreatedBy
, @LastModifiedDate
,
and @LastModifiedBy
. In this example we will see how it can be implemented with very little configurations.
In this example we have an entity class, User which contains information about the table structure. Initial structure is as follows:
@Entity
@Table
public class User {
private Long id;
private String name;
private String username;
private ZonedDateTime created;
private ZonedDateTime modified;
@Id
@GeneratedValue
public Long getId() {
return id;
}
public User setId(Long id) {
this.id = id;
return this;
}
@Column(nullable = false)
public String getName() {
return name;
}
public User setName(String name) {
Assert.hasText(name, "name is required");
this.name = name;
return this;
}
@Column
public String getUsername() {
return username;
}
public User setUsername(String username) {
Assert.hasText(username, "username is required");
this.username = username;
return this;
}
@Column(nullable = false, updatable = false)
public ZonedDateTime getCreated() {
return created;
}
public User setCreated(ZonedDateTime created) {
this.created = created;
return this;
}
@Column(nullable = false)
public ZonedDateTime getModified() {
return modified;
}
public User setModified(ZonedDateTime modified) {
this.modified = modified;
return this;
}
}
As you can see it is a standard implementation of @Entity
JPA class. We would like to keep track when an entry is
created with created
column and when it is modified with modified
column.
In order to enable JPA Auditing for this project will need to apply three annotations and a configuration class.
Those annotations are; @EntityListener
, @CreatedDate
, and @LastModifiedDate
.
@EntityListener
will be the one that is responsible to listen to any create or update activity. It requires
Listeners
to be defined. In this example we will use the default class, EntityListeners
.
By annotating a column with @CreatedDate
we will inform Spring that we need this column to have information on
when the entity is created. While @LastModifiedDate
column will be defaulted to @CreatedDate
and will be updated
to the current time when the entry is updated.
The final look of User
class:
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table
public class User {
private Long id;
private String name;
private String username;
private ZonedDateTime created;
private ZonedDateTime modified;
@Id
@GeneratedValue
public Long getId() {
return id;
}
public User setId(Long id) {
this.id = id;
return this;
}
@Column(nullable = false)
public String getName() {
return name;
}
public User setName(String name) {
Assert.hasText(name, "name is required");
this.name = name;
return this;
}
@Column
public String getUsername() {
return username;
}
public User setUsername(String username) {
Assert.hasText(username, "username is required");
this.username = username;
return this;
}
@CreatedDate
@Column(nullable = false, updatable = false)
public ZonedDateTime getCreated() {
return created;
}
public User setCreated(ZonedDateTime created) {
this.created = created;
return this;
}
@LastModifiedDate
@Column(nullable = false)
public ZonedDateTime getModified() {
return modified;
}
public User setModified(ZonedDateTime modified) {
this.modified = modified;
return this;
}
}
As you can see Person
is now annotated with @EntityListeners
while created
and modified
columns are annotated
with @CreatedDate
and @LastModifiedDate
. Next we will need to create a Configuration
class to enable JpaAuditing.
In this project we have AuditConfiguration class which is responsible to inform Spring Data that we would like
to enable Auditing. This can be achieved with a simple annotation, @EnableJpaAuditing
@Configuration
@EnableJpaAuditing
public class AuditConfiguration {
}
That's it! Our application has JPA Auditing feature enabled. The result can be seen in SpringDataAuditApplicationTests.
There is no better way to verify an implementation other than running some tests. In our test class we have to scenario:
- Create an entity which will have
created
andmodified
fields has values without us assigning them - Update created entity and
created
field will remain to have the same value whilemodified
values will be updated
In the following test we will see that values for created
and modified
are assigned by Spring itself:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataAuditApplicationTests {
@Autowired
private UserRepository userRepository;
private User user;
@Before
public void create() {
user = userRepository.save(
new User().setName("Rashidi Zin").setUsername("rashidi.zin")
);
assertThat(user.getCreated())
.isNotNull();
assertThat(user.getModified())
.isNotNull();
}
// rest of the content is omitted
}
As mentioned earlier, we did not assign values for created
and modified
fields but Spring will assign them for us.
Same goes with when we are updating an entry.
In the following test we will change the username
without changing modified
field. We will expect that modified
field will have a recent time as compare to when it was created:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataAuditApplicationTests {
@Autowired
private UserRepository userRepository;
private User user;
@Test
public void update() {
ZonedDateTime created = user.getCreated();
ZonedDateTime modified = user.getModified();
userRepository.save(
new User()
.setId(user.getId())
.setName(user.getName())
.setUsername("rashidi")
);
User updatedUser = userRepository.findOne(user.getId());
assertThat(updatedUser.getUsername())
.isEqualTo("rashidi");
assertThat(updatedUser.getCreated())
.isEqualTo(created);
assertThat(updatedUser.getModified())
.isGreaterThan(modified);
}
}
As you can see at our final verification we assert that modified
field should have a greater value than it
previously had.
To recap. All we need in order to enable JPA auditing feature in this project are:
@EnableJpaAuditing
@EntityListeners
@CreatedDate
@LastModifiedDate