Tag Archives: Auditing

Simple example of Hibernate Envers

Hibernate envers offer an easy way to track changes to entities managed by hibernate.  This post will show you how to create a very simple hibernate project with one entity and track changes made to that entity.

The project is created using maven, java 8 and hibernate 4.3.6-Final.  The hibernate version is important, if you are using a much older version of hibernate you will need extra configuration in the persistence.xml.

All the code can be found in https://github.com/jwatters1981/blog_code.git

We start with the maven pom.  In the pom we have declared the relevant dependencies needed including hibernate, junit and postgres.  You can use a different database if you wish.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>HibernateEnvers</groupId>
    <artifactId>HibernateEnvers</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-envers</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1100-jdbc41</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>

    </build>
</project>

Next is our last piece of xml configuration, it is the persistence.xml. This should be located in the META-INF
folder for hibernate to find it.

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">
    <persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
        <class>org.acme.hibernate.envers.Project</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="liverpool" />
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/envers" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />

            <property name="hibernate.hbm2ddl.auto" value="create-drop" />

        </properties>
    </persistence-unit>
</persistence>

In the above xml we reference our Project entity in line 6. We also configure out database settings.  The last property is used to create and drop our tables when the application starts.

We can now start to look at the java code, below is the Project entity, this is the entity we will be creating and modifying.  Note the extra annotation @Audited.  This tells hibernate to audit changes made to this entity.  If you don’t specify a table name for the @Audited annotation it will suffix the current table name with _AUD.

package org.acme.hibernate.envers;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.envers.Audited;

@Entity
@Table
@Audited
public class Project implements Serializable {


    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "PROJECT_NAME")
    private String name;

    @Column(name = "DESCRIPTION")
    private String description;

    @Column(name = "OWNER_ID")
    private String ownerId;
    
    public Project()
    {
        super();
    }

    public Project(String name, String description, String ownerId) {
        super();
        this.name = name;
        this.description = description;
        this.ownerId = ownerId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getOwnerId() {
        return ownerId;
    }

    public void setOwnerId(String ownerId) {
        this.ownerId = ownerId;
    }
    
    
}

We are now ready to create a test class to save and update our entity.

package org.acme.hibernate.envers;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.junit.Assert;
import org.junit.Test;

public class PersonTest {

    @Test
    public void testVersioning() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("manager1");
        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin();

        Project project = new Project("Project 1", "Hibernate", "Joe Blogs");

        entityManager.persist(project);

        entityManager.getTransaction().commit();
        entityManager.getTransaction().begin();
        Project project2 = entityManager.find(Project.class, project.getId());
        project2.setOwnerId("New Owner ID");
        entityManager.merge(project2);
        entityManager.getTransaction().commit();
        entityManager.getTransaction().begin();
        project2 = entityManager.find(Project.class, project.getId());
        project2.setOwnerId("New Owner ID 2");
        entityManager.merge(project2);
        entityManager.getTransaction().commit();
        
        entityManager.getTransaction().begin();
        project2 = entityManager.find(Project.class, project.getId());
        project2.setOwnerId("New Owner ID 3");
        entityManager.merge(project2);
        entityManager.getTransaction().commit();
        AuditReader reader = AuditReaderFactory.get(entityManager);
        Assert.assertEquals(4, reader.getRevisions(Project.class,project.getId()).size());
    }
}

To build and run the above project just execute the below command.

mvn clean build

Thats it if you look at the PROJECT_AUD table you can see the records created by hibernate envers