In this article I will give you a brief introduction to Entity auditing with Hibernate, or to be more specific with Hibernate Envers which is since some 3.x version part of the Hibernate core.
And by the way: Envers stays for Entity Versioning.
Why should I care about auditing?
If you work on a larger project (or sometime in the future you will be) auditing would play a role in your application to monitor who changes sensible data. Sometimes monitoring who changed something is not enough: you want to know what has been changed and which values were changed too.
For this you can create some custom solution of your own or use Hibernate Envers, a part of the Hibernate core which provides the functionality to use out of the box.
Just to mention a scenario: you are a developer of a car retail application. Someone sells a car with 80% off the regular price for a luxury automobile — and nobody knows who changed the price. At the end you are guilti because you do not have monitoring and you have to fix this in a very short time frame.
If it sounds desperate and you want to have a solution up your sleeve, continue reading.
The ease of Hibernate Envers
To have Hibernate Envers working you need to import it to your class-path, or if using Maven, as a dependency:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>4.3.10.Final</version>
</dependency>
If you have Envers on your class-path just use the org.hibernate.envers.@Audited annotation on your entity or a property you want to audit:
@Entity
@Table(name = "BOOKS")
@Audited
public class Book {
// ... the body of the entity
}
In this case Hibernate manages automatically the versioning of the entities. It will create a table with the entity’s table’s name and the _AUD suffix. In this example BOOKS_AUD and there it stores all the fields of the entity with two extra columns: REVTYPE and REV.
REVTYPE is the type of the revision, it can take the values add, mod, del for inserting, modifying or deleting respectively.
The REV field holds the revision number of the stored entry.
If you annotate only one or some of the fields of the entity with the @Audited annotation, the *_AUD table will contain the two extra fields of auditing, the fields annotated with @Audited and the id of the entity.
Hibernate creates an extra table called REVINFO in which the REV number is mapped with a timestamp when the change of the entity occured.
Custom revision tables
You can customize the revision table as you wish to extend the core functionality with the information you need. As I mentioned above one such scenario would be to log the current user associated with the application session (in the case of a web application) along with the entity changes.
To do this you need a custom @Entity object which extends the org.hibernate.envers.DefaultRevisionEntity and has the org.hibernate.envers.@RevisionEntity annotation. For the @RevisionEntity you have to add a custom listener class if you want to update data in the table. In this example it will be the user’s name. This listener has to implement the org.hibernate.envers.RevisionListener interface — as seen below.
@Entity
@RevisionEntity(AuditRevisionListener.class)
public class AuditEntity extends DefaultRevisionEntity {
private String username;
// getters and setters
}
public class AuditRevisionListener implements RevisionListener {
@Override
public void newRevision(Object revisionEntity) {
final AuditEntity auditEntity = (AuditEntity) revisionEntity;
// normally you would set here the name of the current user
auditEntity.setUsername("GHajba");
}
}
Switching auditing tables during production
One thing you should care about is switching the audit tables during production (or even test). As soon as you introduce a new table, the revision id (the contents of the REV field in the auditing table) resets and begins to count from 1 (if you do not specify any other sequence to start). This means you have to know when you switched to find the right revisions to the right entries of the revision information.
Conclusion
As you could see, Hibernate offers a nice and easy way to have entities versioned. However again, I just scratched the surface of the possibilities but I hope I could give you a good point to start.
Code Download
Download here Hibernate entity versioning code here.
Sorry, where is it saved the extra info? (in this case the username)