Hi, I’m Thorben Janssen from thoughts-on-java.org. Today I want to show you how to implement a conditional audit with Hibernate Envers. Envers automatically integrates with Hibernate ORM and provides a powerful and easy to use solution to write an audit log As I described in previous videos, you just need to add Envers to your classpath and annotate your entities with Audited. It will then document all insert, update and delete operations and you can even perform complex queries on your audited data and customize the revision information. Sounds quick and easy, right? Well, it is, as long as you audit all changes performed on an entity. But implementing a conditional audit requires more work. By default, Hibernate Envers registers a set of event listeners which are triggered by Hibernate ORM. You need to replace these listeners to customize Envers’ audit capabilities. Hibernate Envers’ provides a set of listeners which are triggered by the event types you can see here on the slide. Let’s say, I’m auditing book entities and I want to ignore all updates of books which are not published. These are all Book entities which’s publishingDate attribute is null. I need to replace the existing listeners for events of EventType.PRE_UPDATE and EventType.POST_UPDATE. That’s a lot easier than you might expect. Let’s take a look at the Book entity first. As you can see here, I annotated this entity with Audited so that Hibernate Envers audits all changes. That’s all you need to do if you want to write a standard audit which documents all changes. But we only want to audit published entities and that requires a few custom event listeners. Hibernate Envers provides the EnversPreUpdateEventListenerImpl. It already implements all the required logic to write the audit information for update operations. The only thing you need to do is to extend this class and ignore all update operations which you don’t want to document in the audit log. I do that in the MyEnversPreUpdateEventListenerImpl class. It extends Envers’ EnversPreUpdateEventListenerImpl and overrides the onPreUpdate method. Within that method, I check if the event was triggered for a Book entity and if the publishingDate is null. If that’s the case, I ignore the event and in all other cases, I just call the method on the superclass. And you can replace the listener of the EventType.POST_UPDATE event in the same way The only difference is that you now need to extend the EnversPostUpdateEventListenerImpl class. I did that here. OK, you have custom listener implementation which ignore all changes to Book entities which don’t have a publishing date. You now just have to tell Hibernate Envers to use your listeners instead of the default ones. You can do that by providing your implementation of Hibernate’s Integrator interface. The easiest way to do that is to copy and adapt the EnversIntegrator class. Hibernate Envers uses this class by default. All event listeners are registered in the integrate method. In this example, I just want to replace the listeners for the EventType.PRE_UPDATE and EventType.POST_UPDATE events. So, I register my implementations instead of Envers’ default ones. You can implement this part as it is required by your application. You can replace all of Envers’ listeners, don’t register listeners for some events or register listeners for other Hibernate EventTypes. The last thing you need to do to use your
custom event listeners is to register your Integrator implementation. You can do that by adding the fully qualified name of your class in the META INF/services/org.hibernate.integrator.spi.Integrator file. OK, that’s all. Let’s give it a try. This test case persists a new Book entity without a publishingDate in the 1st transaction, updates the title in the 2nd transaction and sets the publishingDate in the 3rd transaction. I only replaced the listeners for the EventType.PRE_UPDATE and EventType.POST_UPDATEevents. Hibernate Envers, therefore, audits the INSERT operation of the 1st transaction. But you can see that in the 2nd transaction the custom event listener implementations ignored the update event. And when the 3rd transaction sets the publishingDate, the custom listeners delegate the event handling to Envers’ listener implementation and adds a record to the audit log. OK, that’s it for today. If you want to learn more about Hibernate, you should join the free Thoughts on Java Library. It gives you free access to a lot of member-only content like a cheat for this video and an ebook about the Java 8 support in Hibernate 5 I’ll add the link to it to the video description below. And if you like today’s video, please give it a thumbs up and subscribe below. Bye

Hibernate Envers : How to Implement a Conditional Audit Log
Tagged on:                                 

2 thoughts on “Hibernate Envers : How to Implement a Conditional Audit Log

  • March 24, 2018 at 7:51 pm
    Permalink

    Awesome!

    I'm working with spring boot 2 (Hibernate 5). I had to set up in application.properties:

    spring.jpa.properties.hibernate.envers.autoRegisterListeners=false

    Thank you!

    Reply
  • April 8, 2019 at 6:43 pm
    Permalink

    Hello,
    Thanks for the solution , but i think something is missing :
    When you append a new listener, for example a PostUpdateEventListener, it doesn't mean that EnversPostUpdateEventListener is not active anymore, the system will invoke my listener then hibernate-envers' listener -> it will audit in any case

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *