Auditing in Spring Boot
Tags: auditing, springboot, spring, jpa
Published: 2022-08-19 17:03:02

## What's auditing?

Auditing means tracking and logging transactions related to data, which simply means logging insert, update and delete operations (user and/or date of action).

## How to add creation/update date of an @Entity in Spring?

This can be achieved using different approaches:

- Database built-in solutions: Oracle Database 12c, Db2, MySQL Enterprise Audit...
- Creating database triggers,
- Use a third party tool,
- Create columns of update and create for each entity, and log every change manually to the database (write it completely on your own),
- Using Spring Auditing 💡

This last choice doesn't require touching our entities business logic to add tracking logic, and doesn't require adding additional columns to the entity or additional tables to log changes. 

A headless solution to track your entity, if you are using Spring. We configure it once and use it everywhere:

> Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and the point in time this happened. (spring)

## Implementation

The possible approaches:

**1. Implementation using standard JPA:**
*Uses the entity's table itself to log changes, in this case we can't audit delete operations.*
**2. Implementation using auditing functionality provided by Hibernate:**
*It logs into tables other than the entity's table, which allows to log delete operations.*
**3. Implementation using auditing functionality provided by Spring Data JPA💡:**
*Provides handy annotations for auditing properties, ready for integration with Spring Security, and also cannot be used to log delete operations since it inherits the same flaws of the JPA approach.*

Next we will cover the implementation of auditing with Spring Data JPA.

📝 Checkpoints/Todos:

- Auditing Author Using AuditorAware and Spring Security (allows adding `@CreatedBy`, and `@LastModifiedBy`).
- Enable JPA Auditing by Using `@EnableJpaAuditing`
- Create Generic Auditable Class with Spring Data Annotations `@CreatedDate`, and `@LastModifiedDate`.
- Add Extends from Auditable Class to the entity we want to track.

**1- Create `AuditorAware` implementation that will be used to configure auditing:**
```java
import org.springframework.data.domain.AuditorAware;
import java.util.Optional;

public class AuditorAwareImpl implements AuditorAware<String> {

		// Returning empty instead of user since we're tracking just dates not users
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.empty();
    }

		// Use the following to get the actual connected user
		/*
    public User getCurrentAuditor() {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }

        return ((MyUserDetails) authentication.getPrincipal()).getUser();
    }
    */
}
```
**2- Enable auditing, by adding this configuration class to the spring boot project's configuration directory:**
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfig {
    @Bean
    AuditorAware<String> auditorProvider() {
        return new AuditorAwareImpl();
    }
}
```
**3- Once auditing is enabled we create the Auditable class, that we will extend wherever we want (in our model classes):**
```java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Auditable<U>
{
    @CreatedDate
    @Column(name = "created_date")
    protected Date createdDate;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    protected Date lastModifiedDate;

    // To track the user that modified or created use @LastModifiedBy and @CreatedBy
    
    //@LastModifiedBy
    //protected U lastModifiedBy;

    //@CreatedBy
    //protected U createdBy;

}
```
**4- Last, extend from Auditable class to track changes, example:**
```java
@Data
@Entity
@NoArgsConstructor
@Table(name = "products")
public class Product extends Auditable<String> {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
}
```

The columns `created_date` and `last_modified_date` are automatically added to `products` table in the database, and since `Product` class extends `Auditable` class the `createdDate` and `lastModifiedDate` attributes can be used in the same way `Product`'s other attributes are used.

More on:
[Official docs](https://www.baeldung.com/database-auditing-jpa)