Skip to content

Auditing (Envers)

Squizy integrates with Hibernate Envers to provide automatic entity auditing. When enabled, every change to an entity is recorded as a revision, allowing you to browse the full history of modifications.

Enabling Auditing

Add the @Audited annotation from Hibernate Envers to your entity:

java
@Audited
@SquizyEntity
@Entity
public class Product {

    @Id
    private String reference;

    @NotNull
    private String name;

    @NotNull
    private BigDecimal price;

    // ...
}

Once annotated, Squizy automatically exposes revision history through the REST API:

  • GET /api/{entity}/{id}/revisions — list revisions for a specific record
  • GET /api/{entity}/{id}/revisions/{rev} — get the entity state at a specific revision
  • GET /api/{entity}/revisions/summary — list all revisions for the entity type

Auditing Relationships

Fully Audited (both sides)

When both entities in a relationship are audited:

java
@Audited
@SquizyEntity
@Entity
public class Order {

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderLine> products;
}

@Audited
@SquizyEntity(hidden = true)
@Entity
public class OrderLine {

    @ManyToOne
    private Product product;
}

Non-Audited Target

When the related entity is not audited, use RelationTargetAuditMode.NOT_AUDITED:

java
@Audited
@SquizyEntity
@Entity
public class Address {

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    @ManyToOne
    @NotNull
    private Country country;
}

WARNING

If a related entity is not audited, you must use @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) on the relationship field. Otherwise, Envers will throw an exception at startup.

@OneToMany and Join Tables

Important

When auditing @OneToMany relationships that use a join table (the JPA default for unidirectional @OneToMany), Hibernate Envers requires the join table to also be audited.

Solutions

Use mappedBy — make the relationship bidirectional, which eliminates the join table:

java
// Parent
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", orphanRemoval = true)
private List<Book> books;

// Child
@ManyToOne
@JsonBackReference
private Owner owner;

Use @JoinTable with @AuditJoinTable — explicitly define the join table:

java
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "owner_books")
@AuditJoinTable(name = "owner_books_aud")
private List<Book> books;

Use @JoinColumn — force a foreign key column on the child table:

java
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "owner_id")
private List<Book> books;

Access Control

Viewing audit data requires the audit authority for the entity. See RBAC.