Spring3 min de leitura

Auditoria de entidades JPA com Embeddables e Entity Listeners

Auditoria Automática no JPA: Guia Prático com @Embeddable e @EntityListeners


Muitas vezes, precisamos rastrear quem criou ou modificou um registro e quando isso ocorreu. Embora o uso de @MappedSuperclass seja comum, a utilização de tipos embutidos (@Embeddable) oferece uma alternativa elegante para reutilizar propriedades entre múltiplas entidades.

1. O Modelo de Dados de Auditoria (@Embeddable)

O primeiro passo é encapsular os campos de auditoria em uma classe anotada com @Embeddable. Isso permite que esses quatro campos (created_by, created_on, updated_by, updated_on) sejam tratados como uma única unidade reutilizável.

@Embeddable
public class Audit {
    @Column(name = "created_on")
    private LocalDateTime createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "updated_on")
    private LocalDateTime updatedOn;

    @Column(name = "updated_by")
    private String updatedBy;

    // Getters e setters omitidos para brevidade
}

2. Definindo a Interface Auditable

Para que nosso "ouvinte" de eventos (Listener) consiga manipular os dados de auditoria de forma genérica, definimos uma interface que as entidades deverão implementar.

public interface Auditable {
    Audit getAudit();
    void setAudit(Audit audit);
}

3. O Ouvinte de Eventos (@EntityListeners)

O AuditListener é o coração da automação. Ele utiliza anotações de ciclo de vida do JPA para interceptar operações de banco de dados:

@PrePersist: Executado antes da inserção (INSERT). @PreUpdate: Executado antes da atualização (UPDATE).

public class AuditListener {
    @PrePersist
    public void setCreatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();
        if (audit == null) {
            audit = new Audit();
            auditable.setAudit(audit);
        }
        audit.setCreatedOn(LocalDateTime.now());
        audit.setCreatedBy(LoggedUser.get()); // Utilitário para obter usuário logado
    }

    @PreUpdate
    public void setUpdatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();
        audit.setUpdatedOn(LocalDateTime.now());
        audit.setUpdatedBy(LoggedUser.get());
    }
}

4. Aplicando às Entidades

Agora, basta aplicar a anotação @EntityListeners e implementar a interface Auditable em suas entidades, como no exemplo da classe Post:

@Entity(name = "Post")
@Table(name = "post")
@EntityListeners(AuditListener.class)
public class Post implements Auditable {
    @Id
    private Long id;

    @Embedded
    private Audit audit;

    private String title;
    
    // Getters e setters
}

5. Resultados na Prática

Ao persistir ou atualizar uma entidade, o Hibernate cuida automaticamente das colunas de auditoria.

Exemplo de INSERT gerado automaticamente:

INSERT INTO post (created_by, created_on, updated_by, updated_on, title, id)
VALUES ('Joao', '2026-04-20 11:17:40.552', NULL, NULL, 'Título do Post', 1)

Exemplo de UPDATE gerado automaticamente:

UPDATE post 
SET created_by = 'Joao', created_on = '2026-04-20 09:17:40.552', 
    updated_by = 'Maria', updated_on = '2026-04-20 09:17:40.605', 
    title = 'Título Atualizado' 
WHERE id = 1

Conclusão


Esta abordagem permite reutilizar tanto a estrutura de dados (via @Embeddable) quanto o comportamento (via @EntityListeners). É uma solução limpa que mantém suas entidades de negócio focadas, enquanto a infraestrutura de auditoria funciona silenciosamente nos bastidores.

← Voltar aos Artigos