Reputation: 13213
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?
Upvotes: 12
Views: 9306
Reputation: 404
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();
...
}
}
EDIT: I just realized that @deniss-s updated his answer (likely after reading mine), but his answer is still incorrect: AuditReader is still created as a singleton, while a new instance must be created each time.
Upvotes: 9
Reputation: 43
I can't create a comment, so I'll duplicate Giulio Pulina's answer. His answer is indeed more correct than those with more upvotes. Other answers are also working, but only as long as there is a connection to the database. In case of loss of connection with the database (restart of the container with the database), AuditReader becomes inoperable. Therefore, the current response, when the AuditReader is created before each request, is most preferable.
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();
...
}
}
Upvotes: 1
Reputation: 263
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.
Upvotes: 12
Reputation: 3233
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());
}
Upvotes: 5
Reputation: 1220
AuditReaderFactory only has two static methods. Can you autowire a SessionFactory object or your EntityMananger? Looks like either would give you what you want, which is access to an AuditReader.
AuditReaderFactory.get(sessionFactory.getCurrentSession())
EDIT this post has some detail or wiring SessionFactory if needed
Upvotes: 2