Is there a way to selectively disable auditing for entity modifications in tests?

I have several entities that need to be audited. Auditing is implemented by using the following JPA event listener, as described in this blog: How to audit entity modifications using the JPA @EntityListeners, @Embedded, and @Embeddable annotations

public class AuditListener {

    private final User user = User.builder()
            .id(NumberUtils.LONG_MINUS_ONE)
            .login("admin")
            .build();

    @PrePersist
    public void setCreatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();
        if (isNull(audit)) {
            audit = new Audit();
            auditable.setAudit(audit);
        }
        audit.setDateCreate(ZonedDateTime.now());
        audit.setUserCreate(user);
    }

    @PreUpdate
    public void setUpdatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();
        audit.setDateUpdate(ZonedDateTime.now());
        audit.setUserUpdate(user);
    }
}

I annotate the entities that need to be automatically audited as follows:

@EntityListeners(AuditListener.class)
public class Document implements Auditable {
    @Embedded
    private Audit audit;
}

In a test environment(unit tests, e2e) for some tests I want to be able to manually set the audit. Is that possible? I have previously tried to solve this problem with Spring AOP but unfortunately without success. I think, that Spring AOP could allow selectively set the audit by using various combinations in pointcuts.

Is there a way to selectively set auditing by using JPA features?

I would be very grateful for the information.

Thanks to all.

You have several ways to accomplish this:

ThreadLocal variable

Your test could instantiate and set a ThreadLocal that the AuditListener callbacks check and based on your logic, you could dicate whether the @PrePersist or @PreUpdate callbacks mutate state.

Spring Dependency Injection

As of Spring 5.1 and Hibernate 5.3, various Hibernate constructed objects support bean injection from the surrounding dependency injection framework. If you’re in a CDI-based environment, Hibernate would use that. If Spring 5.1 injects its own SpringBeanContainer implementation when it bootstraps Hibernate, then listeners would have injection happened by Spring.

What I would do here is move the pre-persist and pre-update logic into an injected component and then have the your AuditListener act as a delegator to the component during the JPA callbacks. This would allow you to inject different component implementations depending on application/test/environment needs.

1 Like