Table of Contents
Hibernate Envers is the frameworks for auditing entities. As the name suggests Hibernate Envers is developed on top of Hibernate, it will on Hibernate and Hibernate implemented JPA. Hibernate Envers provides easy auditing, versioning solution for entity classes.
Advantages of Hibernate Envers:
- Auditing of all mappings defined by JPA specification.
- Auditing Hibernate specific mappings which extends the JPA specification.
- Logging data for each revision using revision entity.
- Querying audited data of an entity and its association.
- Database independent auditing.
- Querying entity revisions similar to entities.
Implementing Hibernate Envers in an application
Annotate entity or entity properties using @Audited annotation, please make sure that entity primary keys will be of immutable class.
Hibernate Envers uses the same concept used source code versioning tools called revision. A revision identifies a collection of changes to entities and their associations for all audited attributes that occurred within the boundary of a transaction. These revisions are global and numeric.
Some of the important annotations used in Hibernate Envers
- @Audited: we can apply this annotation to either field or a class, when applied to a class, indicates that all of its properties should be audited and when applied to a field, indicates that this field should be audited.
- @NotAudited: When applied to a field, indicates that this field should not be audited.
- @AuditingOverride: The annotation is used to override the auditing behavior of a superclass or single property inherited from super class type, or attribute inside an embedded component.
- @AuditingOverrides: The annotation is used to override the auditing behavior for one or more fields (or properties) inside an embedded component.
- @AuditTable: By default, Hibernate adds the “_AUD” suffix to the table name of the audited entity. We can define a different table name with the @AuditTable annotation or by configuring a different prefix or suffix in the configuration.
- @RevisionNumber: Marks a property which will hold the number of the revision in a revision entity,Values of this property should form a strictly-increasing sequence of numbers. The value of this property won’t be set by Envers. Most of the cases, this should be an auto-generated database-assigned primary id.
- @RevisionTimestamp: Marks a property which will hold the timestamp of the revision in a revision entity, the value of this property will be automatically set by Envers.
- @AuditJoinTable: This annotation is used to audit the entity relations, name of the audit join will be by default to a concatenation of the names of the primary table of the entity owning the association and of the primary table of the entity referenced by the association.
- If we are using Secondary Table(s) in entity, then audit tables for them will be generated in the same way (by adding the prefix and suffix). If you wish to overwrite this behavior, you can use the @SecondaryAuditTable and @SecondaryAuditTables annotations.
- We can override auditing behavior of some fields/properties inherited from @MappedSuperclass or in an embedded component, you can apply the @AuditOverride annotation on the subtype or usage site of the component.
- If parent entity is annotated with @Audited and associates entities are not audited, then it will try to fetch the latest associations, if it not found then it will throw exception, in this case we can @NotFound annotation to ignore the exception.
Hibernate Configuration Properties for Envers
- hibernate.envers.audit_table_prefix :String that will be prepended to the name of an audited entity to create the name of the entity and that will hold audit information.
- hibernate.envers.audit_table_suffix (default: _AUD):String that will be appended to the name of an audited entity to create the name of the entity and that will hold audit information. We can override using @AuditTable annotation for an entity.
- hibernate.envers.revision_field_name (default: REV):Name of a field in the audit entity that will hold the revision number.
- hibernate.envers.revision_type_field_name (default: REVTYPE ):Name of a field in the audit entity that will hold the type of the revision.
Usage of Hibernate Envers
- We need to implement RevisionListener for creating new revision entity, by implementing newRevision(Object revisionEntity)
- Create a revision entity class either by extending DefaultRevisionEntity or create simple plain java object which contains setter/getter methods, if we extends DefaultRevisionEntity then two attributes annotated with @RevisionNumber and @RevisionTimestamp will be added. Annotate this class with @RevisionEntity so that it will be used in creating revisions. If multiple annotations are marked with @RevisionEntity annotation then it will throw an error.
Reading Audited Entities
AuditReader is the class to read the entity revisions, it has various methods to read the entity revisions of an entity id. It also allows to get access to lists of revisions associated with an entity type or restricted by a date range. The API also provides a way to get the revision metadata so we can know when a change occurred plus any additional custom attributes we may have stored on the revision entity based on implementation needs.
AuditReader reader = AuditReaderFactory.get( entityManager ); Event firstRevision = reader.find( Event.class, 2L, 1 );
Hibernate Envers add a series of Hibernate session listeners and it will be auto registered.
- For creating conditional auditing we need to turn off the auto registration of event listeners, hibernate.envers.autoRegisterListeners by setting this property to false.
- Hibernate envers provide the event listeners for different operations like for insert, update and delete, suppose if we want to add conditional audit for insertion, then create a class which extends EnversPostInsertEventListenerImpl class, add custom logic in it.
- Create custom implementation of Integrator or extends EnversIntegrator class and use previously created event listener instead of default one.
- Hibernate Envers will use META-INF/services/org.hibernate.integrator.spi.Integrator file for loading Integrator class, create a above file and write the fully qualified name of the class implementing the interface so that it will be loaded instead of default one.
Tracking entity names modified during revisions
By default, entity types that have been changed in each revision are not being tracked. This implies the necessity to query all tables storing audited data in order to retrieve changes made during specified revision. Envers provides a simple mechanism that creates REVCHANGES table which stores entity names of modified persistent objects. Single record encapsulates the revision identifier (foreign key to REVINFO table) and a string value.
We can implement this in multiple ways:
- Set org.hibernate.envers.track_entities_changed_in_revision parameter to true. In this case org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity will be implicitly used as the revision log entity.
- Create a custom revision entity that extends org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity class.
- Mark an appropriate field of a custom revision entity with @org.hibernate.envers.ModifiedEntityNames annotation. The property is required to be of Set<String> type.
Hibernate Envers is the framework for providing the auditing in an easier way, we can also customize the Hibernate default behavior, easily can read the entity revisions, and also it is database indepent.