Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access AuditReaderFactory in spring boot application?

I am using spring boot and spring data jpa. I am also using hibernate envers and I need access to AuditReaderFactory so that I can write Audit Queries.

Since, its a spring boot and spring data jpa, everything is auto configured. So when I do this,

@Autowired
AuditReaderFactory auditReaderFactory;

It doesn't work. I get the following error.

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.envers.AuditReaderFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency

How do I get a proper reference to AuditReaderFactory in my repository classes?

like image 245
ashishjmeshram Avatar asked Mar 28 '16 08:03

ashishjmeshram


People also ask

How do I enable JPA auditing?

Enabling JPA Auditing. To start, we want to enable auditing via annotation configuration. In order to do that, we add @EnableJpaAuditing on our @Configuration class: @Configuration @EnableTransactionManagement @EnableJpaRepositories @EnableJpaAuditing public class PersistenceConfig { ... }

How do you implement audit logs in spring boot?

Spring Boot JPA Audit Logging Example Spring Data helps you keep track of who created or modified an entity, as well as when it happened. To leverage this auditing functionality, you must provide auditing metadata to your entity classes, which can be defined using annotations or by implementing an interface.


3 Answers

Create configuration class such as AuditConfiguration.java:

import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManagerFactory;

@Configuration
public class AuditConfiguration {

    private final EntityManagerFactory entityManagerFactory;

    AuditConfiguration(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }

    @Bean
    AuditReader auditReader() {
        return AuditReaderFactory.get(entityManagerFactory.createEntityManager());
    }
}

After that you can autowire AuditReader in your component classes.

like image 106
deniss-s Avatar answered Oct 23 '22 12:10

deniss-s


Following up on above answer, and linked question, I found this to work. (Would be nice if this can be turned into an autowire of the reader directly somehow)

@Autowired
private EntityManagerFactory factory;

public void stuff() {
    AuditReader audit = AuditReaderFactory.get(factory.createEntityManager());
}
like image 41
Jay Avatar answered Oct 23 '22 13:10

Jay


In my opinion, @deniss-s answer (top-voted one) is not correct because EntityManager must not be reused outside of the context of a transaction (see https://stackoverflow.com/a/9375891/554117), while the solution makes use of it as a singleton.

A correct retrieval of AuditReader looks like this:

public class AuditRepository {

    @PersistenceContext
    private EntityManager entityManager;

    private AuditReader getAuditReader() {
        return AuditReaderFactory.get(entityManager);
    }
 
     public Optional<T> getRevision() {
         final AuditReader auditReader = getAuditReader();
         ...
    }

}

like image 3
Giulio Pulina Avatar answered Oct 23 '22 13:10

Giulio Pulina