DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Manage Hierarchical Data in MongoDB With Spring
  • MongoDB With Spring Boot: A Simple CRUD
  • Spring Boot Application With Spring REST and Spring Data MongoDB
  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps

Trending

  • Why Stable RAG Answers Can Still Hide Unstable Evidence
  • Good Data, Bad Metric: A Mutation Testing Pattern for Analytics Engineering
  • Observability for Agents and Workflows: Tracing Prompts, Tool Calls, and Business Outcomes End-to-End
  • Liquid Glass, Material 3, and a Lot of Plumbing
  1. DZone
  2. Data Engineering
  3. Databases
  4. Spring Data: Data Auditing Using JaVers and MongoDB

Spring Data: Data Auditing Using JaVers and MongoDB

By 
Anicet Eric user avatar
Anicet Eric
·
Nov. 16, 20 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
23.4K Views

Join the DZone community and get the full member experience.

Join For Free

Recently I was looking for some simple options to track all changes to entities in all my microservices. After researching, I discovered the Java library named JaVers. It is designed as a framework for auditing changes in object-oriented data.

In this post, we’ll see how to use JaVers in a simple Spring Boot application and MongoDB environment to track changes of entities.

Prerequistes

  • Spring Boot 2.
  • Maven 3.6.1.
  • JAVA 8.
  • Mongo 4.4.

What is JaVers

JaVers is an audit log framework that helps to track changes of entities in the application. 

The usage of this tool is not limited to debugging and auditing only. It can be successfully applied to perform analysis, force security policies and maintaining the event log, too.

Why use JaVers

  • It is open source and free to use.
  • JaVers is written in Java 8 and can be run on JRE 8 or higher.
  • It is compatible with both traditional relational relational database systems as well as NoSQL systems. This makes migration between RDBMS and NoSQL much smoother.
  • Easy integration with Spring and Spring Boot.

Setup Spring Boot Project

To integrate JaVers in your application you just need to include the JaVers dependency in you project’s build.gradle or pom.xml file. 

XML
xxxxxxxxxx
1
 
1
<dependency>
2
    <groupId>org.javers</groupId>
3
    <artifactId>javers-spring-boot-starter-mongo</artifactId>
4
    <version>5.13.2</version>
5
</dependency>


Shell
xxxxxxxxxx
1
 
1
compile 'org.javers:javers-spring-boot-starter-mongo:5.13.2'

JaversRepository Configuration

JaVers starters rely on Spring Data starters.  it offers an option to use a dedicated Mongo database for JaVers data.

YAML
xxxxxxxxxx
1
 
1
javers:
2
  mongodb:
3
    host: localhost
4
    port: 27017
5
    authentication-database: admin
6
    database: <<databasemane>>
7
    username: <<dbuser>>
8
    password: <<dbpassword>>


Or

YAML
xxxxxxxxxx
1
 
1
javers:
2
  mongodb:
3
    uri: mongodb://<<dbuser>>:<<dbpassword>>@localhost:27017/<<databasemane>>&authSource=admin


If javers.mongodb property is defined, either host or uri has to set. If so, an application’s data and JaVers data are stored in different databases. 

Audit Annotations

JaVers is based on annotations: @JaversSpringDataAuditable and @JaversAuditable. 

@JaversSpringDataAuditable annotation is used to audit JPA repositories.

Java
xxxxxxxxxx
1
 
1
@JaversSpringDataAuditable
2
    public interface EmployeeRepository extends MongoRepository<Employee, String> {
3
}


By adding this annotation, you create an audit entry for each create, update or delete operation you perform in the database.

In case of a custom repository or If you aren't using Spring Data repositories, annotate all data-changing methods with @JaversAuditable.

Java
xxxxxxxxxx
1
13
 
1
@JaversAuditable
2
public User save(User user) {
3
    ...//
4
}
5
@JaversAuditable
6
public User update(User user) {
7
    ...//
8
}
9
10
@JaversAuditable
11
public void delete(User user) {
12
    ...//
13
}

Trying it Out

Now let's try to change the data. for this, we use the Postman tool to run the endpoints.

testing API in Postman

we notice that JaVers added two new collections in our MongoDB database after saving the employee document.

Application file structure

  • jv_head_id — one document with the last CommitId,
  • jv_snapshots — domain object snapshots. Each document contains snapshot data and commit metadata.

In the jv_snapshots collection, there are three types of documents for auditing a document.

  • INITIAL: Create operation in the database.
  • UPDATE: Update operation.
  • TERMINATE: Delete operation has been performed.

When creating the employee document, we can see in jv_snapshots:

creating employee document

  • commitMetadata: This includes valuable information such as the author of the change, the time of the event in local (commitDate) and UTC (commitDateInstant). 
  • globalId: Contains information about the entity being modified and its database id.
  • state: Contains all the field values of the entity being modified. Please note that this is the state of the object after the change has been performed.
  • changedProperties: This includes the fields that have been modified in this audit log entry. Since this is a creation operation, all fields have been included in the changed properties array.

Let's start the update operation:

updating the operation

Notice that a new document has been created with type UPDATE and the version has been incremented to 2. 

Finally, let's run the delete operation:

deleting the operation

Since the object has been deleted, the entry log type here is TERMINATE. Notice that the changed properties array is empty.

Author Provider

Each committed change in JaVers should have its author.  i.e. the user who made the change.  Moreover, JaVers supports Spring Security out of the box. You need to register an implementation of the AuthorProvider interface, which should return a current user name. 

Java
xxxxxxxxxx
1
17
 
1
@Configuration
2
public class JaversConfiguration {
3
4
    private static final String AUTHOR = "aek author";
5
6
    @Bean
7
    public AuthorProvider provideJaversAuthor() {
8
        return new SimpleAuthorProvider();
9
    }
10
11
    private static class SimpleAuthorProvider implements AuthorProvider {
12
        @Override
13
        public String provide() {
14
            return AUTHOR;
15
        }
16
    }
17
}


In this article, I created a simple custom implementation of the AuthorProvider interface.

Retrieving Audit Information From JaVers Snapshots Repository

 JaVers provides its own JaVers Query Language (JQL). It is a simple, fluent API which allows you to query JaversRepository for changes of a given class, object or property.

Data history can be fetched from JaversRepository using javers.find*() methods in one of three views: Shadows, Changes, and Snapshots.

  • Shadow is a historical version of a domain object restored from a snapshot.
  • Change represents an atomic difference between two objects.
  • Snapshot is a historical state of a domain object captured as the property:value map.

Let's take a look at some examples:

When I want to retrieve all the changes made to the Employee collection. 

curl --location --request GET 'http://localhost:8080/audit/employees'

Shell
xxxxxxxxxx
1
28
 
1
<pre>Changes:
2
        Commit 5.00 done by aek author at 14 nov 2020, 14:30:11 :
3
        * changes on com.java.audit.springdatamongojavers.domain.Employee/5fafdbb15be81677928fbbb7 :
4
        - 'email' value changed from 'johndoe.emal.com' to 'john.email.com'
5
        - 'firstName' value changed from 'John' to 'Doe'
6
        - 'lastName' value changed from 'Doe' to 'John'
7
        Commit 4.00 done by aek author at 14 nov 2020, 14:29:21 :
8
        * new object: com.java.audit.springdatamongojavers.domain.Employee/5fafdbb15be81677928fbbb7
9
        * changes on com.java.audit.springdatamongojavers.domain.Employee/5fafdbb15be81677928fbbb7 :
10
        - 'email' value changed from '' to 'johndoe.emal.com'
11
        - 'firstName' value changed from '' to 'John'
12
        - 'id' value changed from '' to '5fafdbb15be81677928fbbb7'
13
        - 'lastName' value changed from '' to 'Doe'
14
        Commit 3.00 done by aek author at 14 nov 2020, 13:48:51 :
15
        * object removed: com.java.audit.springdatamongojavers.domain.Employee/5fafbbc7c3f606329bd51e7c
16
        Commit 2.00 done by aek author at 14 nov 2020, 13:37:02 :
17
        * changes on com.java.audit.springdatamongojavers.domain.Employee/5fafbbc7c3f606329bd51e7c :
18
        - 'email' value changed from 'johndoe.emal.com' to 'john.email.com'
19
        - 'firstName' value changed from 'John' to 'Doe'
20
        - 'lastName' value changed from 'Doe' to 'John'
21
        Commit 1.00 done by aek author at 14 nov 2020, 12:13:11 :
22
        * new object: com.java.audit.springdatamongojavers.domain.Employee/5fafbbc7c3f606329bd51e7c
23
        * changes on com.java.audit.springdatamongojavers.domain.Employee/5fafbbc7c3f606329bd51e7c :
24
        - 'email' value changed from '' to 'johndoe.emal.com'
25
        - 'firstName' value changed from '' to 'John'
26
        - 'id' value changed from '' to '5fafbbc7c3f606329bd51e7c'
27
        - 'lastName' value changed from '' to 'Doe'
28
</pre>


Properties are matched by name, and their values are compared, without paying much attention to the actual Employee class.

JaVers can have different applications, from debugging to complex analysis. The official documentation presents several examples of use.

The complete source code can be found in my GitHub repository.

Spring Framework Data (computing) Spring Data Relational database Database MongoDB Spring Boot application Spring Security Document

Opinions expressed by DZone contributors are their own.

Related

  • Manage Hierarchical Data in MongoDB With Spring
  • MongoDB With Spring Boot: A Simple CRUD
  • Spring Boot Application With Spring REST and Spring Data MongoDB
  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook