Spring Data JPA Auditing using AuditorAware
In this article, we’ll explore the Spring Data JPA Auditing using AuditorAware. In every business application, we need to audit every change happening in data like insert, update, and delete operation. Spring Data JPA auditing helps us in various ways to track user activities. To enable auditing in your application you must add @EnableJpaAuditing to configuration class.
Spring Data JPA framework provides an abstract layer over traditional JPA by extending it. Spring Data JPA improves the implementation of data access layers by reducing the developer’s effort. You just write repository interfaces; custom finder methods and Spring will provide implementation automatically.
1. What we’ll build
In this tutorial, we are going to audit UserEntity and maintain it’s createdDate, createdBy, lastModifiedDate, and lastModifiedBy data.
2. What we’ll need
- About 20 minute
- JDK 1.8 or later
- Spring Boot 2.2.2.RELEASE
- Spring Data JPA 2.2.3.RELEASE
- Gradle 4+ or Maven 3.2+
- MySQL Database
- Your favorite IDE:
- Spring Tool Suite (STS)
- Eclipse
- IntelliJ IDEA
3. Dependencies Required
Here is the pom.xml file including the required dependencies used in this project.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>4. Project Structure
The final project structure of our application in STS 4 IDE will look like as follows:

5. Entities
5.1 AuditEntity
First, we create AuditEntity abstract class which will be superclass to all our entity and holds data like id, createdDate, createdBy, lastModifiedBy, and lastModifiedDate.
AuditingEntityListener class provides call-back methods that are used to update and persist information on updating or persisting entities and @EntityListeners specify listener classes and to register our AuditingEntityListener class.
package org.websparrow.entity;
import java.util.Date;
import javax.persistence.*;
import org.springframework.data.annotation.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@CreatedBy
protected String createdBy;
@CreatedDate
@Temporal(TemporalType.TIMESTAMP)
protected Date createdTime;
@LastModifiedBy
protected String lastModifiedBy;
@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
protected Date lastModifiedDate;
// Generate Getters and Setters...
}Spring data annotations used:
@CreatedDate: represents the date when the field was created.@CreatedBy: represents the principal(user) that created the entity.@LastModifiedDate: represents the date the entity was recently modified.@LastModifiedBy: represents the principal(user) that recently modified the entity.@MappedSuperclass: represents that this class is parent class and will be extended by other audited entities.
Note:
@MappedSuperclassis not an entity in JPA. This class will not be associated with any table. The child class which inherits@MappedSuperclassannotated class will persist properties of parent class and will be associated with mapped table via using@Entityannotation.
5.2 UserEntity
UserEntity will extend AuditEntity and persists its information to the mapped table.
package org.websparrow.entity;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
@Entity
@Table(name = "user")
@DynamicUpdate
@DynamicInsert
public class UserEntity extends AuditEntity {
private String firstName;
private String lastName;
// Generate Getters and Setters...
}6. Auditing Author using AuditorAware
JPA needs information about currently logged in user so for that we need to implement the AuditorAware interface and override its getCurrentAuditor() method to fetch current logged in user. JPA can audit the created date and modified date by using the system’s current time but for auditor information.
package org.websparrow.config;
import java.util.Optional;
import org.springframework.data.domain.AuditorAware;
public class AuditAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("lucifer");
}
}Here we have hardcoded logged in user for simplicity, but if you use Spring Security you can use the below class to get current logged in user.
package org.websparrow.config; import java.util.Optional; import org.springframework.data.domain.AuditorAware; public class SpringSecurityAuditorAware implements AuditorAware<String> { public Optional<String> getCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext() .getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { return null; } return ((MyUserDetails) authentication.getPrincipal()).getUsername(); } }
7. @EnableJPAAuditing
Now we will add @EnableJpaAuditing to configuration class and create a bean of AuditAware and provide its reference to @EnableJpaAuditing.
package org.websparrow.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorRef")
public class AuditConfiguration {
@Bean
public AuditAware auditorRef() {
return new AuditAware();
}
}8. Controller
Create an UserController class to access the application. For time being, we have hardcoded the user’s details. createUser() method insert the two users into the database and updateUser() update user based on the passed user id.
package org.websparrow.controller;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.websparrow.entity.UserEntity;
import org.websparrow.repo.UserRepository;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@PostMapping
public List<UserEntity> createUser() {
// First User
UserEntity userEntity1 = new UserEntity();
userEntity1.setFirstName("Manish");
userEntity1.setLastName("Fartiyal");
// Second User
UserEntity userEntity2 = new UserEntity();
userEntity2.setFirstName("Atool");
userEntity2.setLastName("Ray");
List<UserEntity> userList = Arrays.asList(userEntity1, userEntity2);
System.out.println("User created");
return userRepository.saveAll(userList);
}
@PutMapping
public UserEntity updateUser() {
// Update User
UserEntity userEntity = userRepository.findById(2L).get();
userEntity.setFirstName("Atul");
userEntity.setLastName("Sharma");
System.out.println("User updated");
return userRepository.save(userEntity);
}
}9. application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/spring_prod
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true10. Start the application
package org.websparrow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDataAuditingApp {
public static void main(String[] args) {
SpringApplication.run(SpringDataAuditingApp.class, args);
}
}11. Test the application
To test the application, start the application and hit the following endpoint in the Postman client. As we have already hardcoded logged in user “lucifer” in AuditAware class.
11.1 Creating new users:
Endpoint: http://localhost:8080/users
HTTP Method: POST
You will get below response in you the Postman client.
[
{
"id": 1,
"createdBy": "lucifer",
"createdTime": "2020-06-27T12:28:48.583+0000",
"lastModifiedBy": "lucifer",
"lastModifiedDate": "2020-06-27T12:28:48.583+0000",
"firstName": "Manish",
"lastName": "Fartiyal"
},
{
"id": 2,
"createdBy": "lucifer",
"createdTime": "2020-06-27T12:28:48.651+0000",
"lastModifiedBy": "lucifer",
"lastModifiedDate": "2020-06-27T12:28:48.651+0000",
"firstName": "Atool",
"lastName": "Ray"
}
]11.2 Update existing user: Now changed logged in user to “grace” in AuditAware class.
Endpoint: http://localhost:8080/users
HTTP Method: PUT
You will get updated data of the user in the response of Postman client.
{
"id": 2,
"createdBy": "lucifer",
"createdTime": "2020-06-27T12:28:49.000+0000",
"lastModifiedBy": "grace",
"lastModifiedDate": "2020-06-27T12:34:09.384+0000",
"firstName": "Atul",
"lastName": "Sharma"
}12. Conclusion
In this article, we have learned how to audit insert, update of an entity. But this method won’t audit the delete functionality of an entity. As Spring Data JPA provides an abstraction layer over JPA but both JPA and Spring Data JPA fails to audit delete functionality.
Download Source Code: spring-data-jpa-auditing-using-auditoraware.zip