Mixing Spring Data Envers and QueryDSL - spring-data

I'm using a global custom repository in my project which extends QueryDslJpaRepository:
public class CustomPagingAndSortingRepositoryImpl<T, ID extends Serializable> extends QueryDslJpaRepository<T, ID>
implements CustomPagingAndSortingRepository<T, ID> {
And the interface:
public interface CustomPagingAndSortingRepository<T, ID extends Serializable>
extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
And then on my configuration I annotate it with:
#EnableJpaRepositories(repositoryBaseClass = CustomPagingAndSortingRepositoryImpl.class)
All is working fine, but now I was trying to add auditing support to my entities by using spring-data-envers and according to the docs I should use a specific repository factory bean class :
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, repositoryBaseClass = CustomPagingAndSortingRepositoryImpl.class)
Now obviously if I do this things won't work because my repositories will now be created through the EnversRevisionRepositoryFactoryBean class and will no longer be of CustomPagingAndSortingRepositoryImpl type.
How can I support something like this? I'm not seeing how since my custom repository need to extend from QueryDslJpaRepository already.

I think the relevant part for you is this method of EnversRevisionRepositoryFactoryBean:
#Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return EnversRevisionRepositoryImpl.class;
}
Here you really want your CustomPagingAndSortingRepositoryImpl returned. So I would try the following:
extend EnversRevisionRepositoryFactoryBean and overwrite getRepositoryBaseClass to return your CustomPagingAndSortingRepositoryImpl.
Make CustomPagingAndSortingRepositoryImpl extend EnversRevisionRepositoryImpl.

Related

Spring Data Jpa Query methods are not invoking the repositoryBaseClass

I have a repository base class as defined below.
#NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
}
public class BaseRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInfo, EntityManager entityMgr) {
super(entityInfo, entityMgr);
}
// ...
}
#Configuration
#EnableJpaRepositories(basePackages = "org.example",
repositoryBaseClass = BaseRepositoryImpl.class)
public class BaseConfig {
// additional JPA Configuration
}
I have defined a business repository class and a query method as seen below.
#Repository
public interface CarRepository extends BaseRepository<Car, Long> {
#Query("SELECT c FROM Car c Where active = 1")
List<Car> findAllActiveCars();
}
I have a test class which invokes the findAllActiveCars(). I am getting the expected results. But, that query method is not invoking any of the methods in BaseRepository class. How to customize the return values of the query methods?
You didn't show the methods that you did implement, so it is not clear why they don't get called, but since you want to decrypt entity fields, consider listening to JPAs entity lifecycle events. #PostLoad should be able to do the trick.
https://docs.jboss.org/hibernate/core/4.0/hem/en-US/html/listeners.html

spring data repository Implenation

I am using Spring DATA JPA and selected #Query annotation for creating queries (instead of using NamedQueries and Queries created from MethodName)
I have a data repository as below
public interface EventRepository extends CrudRepository<Event, Long> {
#Query("select e from Event e where e.name = :eventName)
public List<Event>findEventByName(String eventName );
}
Interface looks good and its enough as per Spring reference doc.
But I need a impl class because I need many other methods in addition to above.
I am facing 2 issues when I create EventRepositoryImpl java implementing EventRepository
Its asking to implement all the methods in EventRepository, findEventByName method is self contained in interface and why I need implement it again in Impl class?
Its asking to implement all the methods in CrudRepository, I know its per OOPS design, But there many methods
So, for these issues can I define my EventRepositoryImpl as abstract,
this seems to be working fine.
But do I need to worry about anything else, when Spring uses a abstract class as a bean.
or is there an elegant way to solve this issue.
Appreciate your help.
You do not have to implement all of these methods neither create an abstract class. Take a look into official documentation.
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
// Declare query methods here
}

Add customer behaviour to all spring data Jpa repositories in CDI context

Am successfully injecting jpa repositories using CDI. I wanted to add custom behaviour(soft deletes) to all repositories. When using spring I can enable customer behaviour by specifying the repository base class
#EnableJpaRepositories(repositoryBaseClass = StagedRepositoryImpl.class)
How do I specify the same in CDI? Thanks in advance.
To add custom behaviour to Jpa Repositories(in your case for delete),
1. Create a base repository like below:
#NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
#Override
default void delete(T entity){
// your implementation
}
}
2. Now inherit Jpa Repositories from custom repository(i.e BaseRepository) like below:
public interface EmployeeRepository extends BaseRepository<Employee, Long> {
}
3. Inject your repository into Service class and call the delete method.
#Service
class EmployeeService {
#Inject
private EmployeeRepository employeeRepository;
public void delete(Long id) {
employeeRepository.delete(id);
}
}
Now whenever you call delete on repositories which are child of BaseRepository, your custom implementation for delete will be invoked.
Here is the way to add custom logic to your repositories:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
Basically you create a custom repository named {YourRepositoryName}Custom
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
And implement it:
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
Your main repository should extend the custom one.
Hope this helps!

How to pass jpql to query method in spring jpa?

Our project involves hundreds of tables/entities, so it's boring to create a single repository for every entity. We want to create a generic repository for common query use which might have a below look:
#Repository
public interface GenericRepo extends JpaRepository<Ctmpdis,Integer> {
public List findByQl(String jpql,Map params);
}
I want to pass concrete jpql to the method on the fly so that we don't have to create so many repos just need one to do all the variable queries.The problem of this idea is I don't know how to pass a query to repo and make it work. Does anybody know how to do it and is it possible? Thanks
You could implement a custom repository, here is an example
public interface MyRepository<T, ID extends Serializable>
extends JpaRepository<T, ID> {
public List findByQl(String jpql,Map params);
}
public class MyRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
#PersistenceContext
private EntityManager entityManager;
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
public List findByQl(String jpql,Map params) {
// implementation goes here
}
}

Wrapping Spring Data JPA with ApsectJ

Is it possible?
Currently I am using some aspects for my MVC controllers, what works really fine. I'm wrapping their responses and I have desired effect.
I also want to do this with Spring Data JPA repositories. But since they're generated based on the interface e.g:
public interface SomeRepository<T extends Some, ID extends Serializable> extends
BaseRepository<T, ID>, JpaSpecificationExecutor<T> {
public List<T> findById(Long id)
}
It generates me controller which is ready to use:
http://localhost:8080/findById?id=1234
I also want to wrap this controller. Is it possible?
This should work:
#Component
#Aspect
public class MyAdvice {
#Before("execution(* com.company.jpa.SomeRepository+.findById(..))")
public void intercept() { ... }
}
Basically, we are telling the framework to intercept the call to the findById method on any sub-class of SomeRepository.
Here is a sample application demonstrating this in action.