Deprecated QuerydslJpaReposiotry does not work anymore - spring

I have a custom repository that needs the functionality of Querydsl as well as PagingAndSortingRepository. Till now my custom repository was like
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QuerydslPredicateExecutor<T> {
// Overriden methods
}
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
// Overriden implementations of methods defined in the interface
}
The great thing about this was that my custom implementation was not very different from the default implementation provided by QuerydslJpaRepository and thus I would use the super class methods with some modifications in mine like
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
#Override
#NonNull
public Optional<T> findOne(#NonNull Predicate predicate) {
return super.findOne(modifierMethod(predicate));
}
#Override
#NonNull
public <U extends T> U save(#NonNull U entity) {
return super.save(otherModifierMethod(entity, false));
}
#Override
#NonNull
public <S extends T> S saveCustom(#NonNull S entity) {
return super.save(otherModifierMethod(entity, false));
}
}
Note that I also have a saveCustom defined by me in the custom interface and I am providing its implementation with the help of the parent class.
This worked great but after Spring Boot 2.1, QuerydslJpaRepository has been deprecated in favour of QuerydslJpaPredicateExecutor. Now this class does not provide implementations of save or delete and thus I cannot use the SimpleJpaRepository methods if my implementation class inherits from QuerydslJpaPredicateExecutor.
In short, I need to reimpelement query and save/delete methods in my custom repository along with some custom methods of mine and I don't want to implement them from scratch. The current deprecation means my implementation can extend either from QuerydslJpaPredicateExecutor which provides implementation of query methods only or from SimpleJpaRepository which means I lose the functionality of querydsl in my implementation.
What I've done till now
To work around this I have created 2 repositories
#NoRepositoryBean
public interface CustomPagingSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
// Only overrides save and delete type of methods and includes my customSave method
#NoRepositoryBean
public interface CustomQuerydslRepository<T, ID> extends QuerydslPredicateExecutor<T> {
// Overrides all methods of the superclass and includes any custom methods of mine
}
and I have implemented them separately like
#NoRepositoryBean
public class CustomPagingSortingRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomPagingSortingRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
#NoRepositoryBean
public class CustomQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaPredicateExecutor<T> implements CustomQuerydslRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
and I inherit these 2 interfaces into my custom interface
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends CustomPagingSortingRepository<T,ID>,CustomQuerydslRepository<T, ID> {
}
I thought this would work but this throws a type error which on close inspection I found to be because Spring is trying to create an implementation of customSave by itself and since it doesn't understand what this method has to do, it throws an error.
I am really in a fix now since the deprecated way was extremely clean and I don't want to implement half a dozen Beans for this to work.
P.S.
I have been thinking using Composition instead of Inheritance to get a handle to SimpleJpaRepository and QuerydslJpaPredicateExecutor and use the methods in them that way but I have a feeling this is going to be against injection and a bad practice.

Related

need help on understand why my customized repository work

I have customized repository to include query methods and customized method. I get it working as blow.
public interface UserRepository extends ElasticsearchRepository<User, String>{
query_method_A();
query_method_B();
My_customized_method();
}
public class UserRepositoryImpl{
My_customized_method(){
//my real implementation
}
}
I don't need to add any annotation. Spring creates two beans.
userRepository : class com.sun.proxy.$Proxy150
userRepositoryImpl : class com.*.repository.impl.userRepositoryImpl
UserRepositoryImpl can't have implements UserRepository , otherwise it complains that it needs to implement those query methods. It works fine.
I was reading a document about Customizing Individual Repositories https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior
It seems that the correct way is to use a fragment repository like below. No annotation is needed. Tested and worked.
public interface UserRepository extends ElasticsearchRepository<User, String>, MyTestRepository
{
query_method_A();
query_method_B();
}
public interface MyTestRepository {
My_customized_method();
}
public class MyTestRepositoryImpl implements MyTestRepository {
My_customized_method(){
//my real implementation
}
}
My question is why does my first custom repository work? It seems more convenient to use though since I only need one Impl class per repository.

How to configure spring JpaRepository to be one of the implementations of an interface

Hello I'm working on a task where based on configuration I need to use either a custom implementation of a repository that uses an api to fetch data or a normal repository that extends a JpaRepository.
So something like this:
public interface PersonRepository {
Person findPersonById(Long id);
}
and the possible implementations for that would be:
public interface PersonDatabaseRepository extends PagingAndSortingRepository<Person, Long>, JpaSpecificationExecutor<Person>{
Person findPersonById(Long id);
}
public class PersonApiRepository extends implements PersonRepository {
public Person findPersonById(Long id) {
return someApiClient.findPersonById(id);
}
}
Is that possible? I know I could add another interface in the upper layer where the implementations would use either PersonDatabaseRepository or PersonApiRepository inside but I was wondering if it would be possible to skip that

Add to Jhipster generator AbstractServices and use them in ElasticsearchIndexService

we suggest an possible improve to jhipster generator future versions.
Is possible you add this abstract classes to the generator and when generator create services extends of that by default, then you reduce a lot of duplication code.
And improve changing JPARepositories list to AbstractServices list in ElasticsearchIndexService.
When we use DTOs:
public abstract class AbstractCrudElasticServiceImpl, S extends ElasticsearchRepository> implements ElasticCrudMethodService { ...
public abstract class AbstractCrudElasticServiceImpl, S extends ElasticsearchRepository> implements ElasticCrudMethodService { ...
When we donĀ“t use DTOs:
public abstract class AbstractCrudDomainElasticServiceImpl> implements ElasticCrudMethodService ...
public abstract class AbstractCrudDomainServiceImpl implements CrudMethodService { ...
Detail:
All services extends any of these Abstract clases without methods.
Abstract clases contains generic methods, you only #Override in subclases when you have a particular behaviour.
And very important we add a new method reindexData in Elastic services that by default calls to findAll, then in ElasticsearchIndexService we call to reindexData of:
=> private final List servicesList;

Dynamic JPA Projections with extended interface and generics

I am looking to use Spring JPA Dynamic Projections to limit the number of fields returned from queries. The table I'm using is wide, but the projection still contains around 10 fields. Therefore I am trying to use Dynamic Projections. The problem seems to be with trying to specify the methods in the repository interface since I first have an interface that extends the JpaRepository using an abstract class and then I have an interface the extends that one using the actual class.
I have tried various approaches to limiting the number of fields and this one seems to be the closest to what I want to use.
Here is my repository on the abstract class User:
#NoRepositoryBean
public interface UserRepository <T extends User> extends JpaRepository<T,
Long>{
<S extends T> S findByLoginName(String loginName);
}
Here is my actual repository on the actual class ConcreteUser:
#Repository
public interface ConcreteUserRepository extends UserRepository<ConcreteUser> {
}
In my service class implementation I have a method call that looks like this:
ConcreteUser user = this.userRepository.findByLoginName(loginName);
This of course returns a large number of fields, so I created an interface that contains the subset of fields that I want called UserProfile. The field names are exactly the same as those in the ConcreteUser. I then added 'implements UserProfile' to the User class. I don't know if that is necessary, but I'm trying to get the generics working so that I can do something like this:
#NoRepositoryBean
public interface UserRepository <T extends User> extends JpaRepository<T,
Long>{
<S extends T> S findByLoginName(String loginName, Class<S> clazz);
}
and then call it like this:
ConcreteUser user = this.userRepository.findByLoginName(loginName, ConcreteUser.class);
UserProfile profile = this.userRepository.findByLoginName(loginName, UserProfile.class;
I've tried various approaches with the generics. I've also tried using my DTO class UserProfileDTO instead of the UserProfile interface.
I am having problems with getting the Generics correct because of the extra level of abstraction.

The method findOne(Example<S>) in the type QueryByExampleExecutor<Contact> is not applicable for the arguments (Long)

The find methods not working for me but in other project work fine .
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entities.Contact;
public interface ContactRepository extends JpaRepository<Contact, Long>{
}
in my controller i call find one but give works.
#RequestMapping(value="/contact/{id}",method=RequestMethod.GET)
public Contact getContact(#PathVariable Long id){
return repo.findOne(id); //here give a error
}
Some CRUD Repository methods got renamed in Spring Data and
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
is one of them. Now you should use the
public interface CrudRepository<T, ID> extends Repository<T, ID> {
Optional<T> findById(ID id);
For more info which methods got renamed see this blog improved-naming-for-crud-repository-methods
There is still a findOne method around but this is from
public interface QueryByExampleExecutor<T> {
<S extends T> Optional<S> findOne(Example<S> example);
which is also an interface of the SimpleJpaRepository. So that is why you got your error, since this method awaits an Example as parameter.

Resources