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;
Related
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.
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.
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.
I have been working on a spring MVC project structure where multiple concrete service classes extends from a Abstract Class.
In my controller, i am trying to autowire the abstract class and choose the implementation based on the user choice. Here's the relevant portion of Controller class:
#Controller
#RequestMapping("/")
public class DashboardController {
#Autowired
LogAnalyzerAbstract logAnalyzer;//new LogAnalyzer();
private static final Log logger =LogFactory.getLog(DashboardController.class);
....
logAnalyzer.process();
}
I want to the controller to use the implementation based on the user input and used the Abstract class LogAnalyzer reference in the further implementaion.
Is my logic valid? Can you guide me through?
If I understand what you ask correctly, what you need to do is to create several Spring-MVC controllers, one for each use case, with its own base path, and to autowire there the abstract service class (or the service interface), based on the bean name of the concrete service (if you use the annotation #Service on concrete service classes, the bean name should be the name of the concrete service class, starting with a lowercase letter).
For example, something like the following:
#Service
public class MyFirstUseCaseService extends AbstractService {
...
}
and in the controller
#Controller
#RequestMapping("/firstUseCaseBaseUrl")
MyFirstUseCaseController {
#Autowired
#Qualifier("myFirstUseCaseService")
private AbstractService service;
....
}
fIn my app I'm using the Spring Security and have defined next classes.
public abstract class AbstractService {
public void save(){
.....
}
}
#Service
#PreAuthorize(SpelAuthorityExpressions.SOME_KIND_OF_ACCESS)
publist class UserService extends AbstractService {
}
#Service
#PreAuthorize(SpelAuthorityExpressions.SOME_KIND_OF_ACCESS_X)
publist class XService extends AbstractService{
}
I need #PreAuthorize annotation from the child class to be applied to the super class methods( for example: save()).Is there any way to achieve it by avoiding to override super class methods?
AbstractService will have more than one child( > 10) wherein each have own #PreAuthorize value.
You can try to use SPEL for that.
Because AFAIK, you must annotate methods or the superclass or the superclass itself, and the annotation must be a plain string (or a static final which is the same). But the string may contain SPEL expressions that will reference the target object. Example if only roles were used :
#PreAuthorize("hasAnyRole(#root.target.requiredRoles)")
public abstract class AbstractService {
public abstract String getRequiredRoles();
public void save(){
.....
}
}
#Service
#PreAuthorize(SpelAuthorityExpressions.SOME_KIND_OF_ACCESS)
publix class UserService extends AbstractService {
#Override
public String getRequiredRoles() {
return "ROLE_USER, ROLE_CLIENT";
}
....
}
As the condition is evaluated by SPEL at runtime, it will use the overriden getter and the list of roles can be defined in child class.
Without knowing what are your requirements for authorization expressions, I cannot be sure if that will do the trick, but I successfully use that for caching methods in a superclass, with keys depending on values in child classes.