Spring Boot : generic Crudrepository interface and generic service interface - java

I wanted to know if i could use the same spring crudRepository and Services interface with multiple classes by attributing a generic type to both of them in order to avoid rewriting the same thing over and over.
i'll try to explain this idea better with an example;
imagine if we had two different classes "Dog" and "Cat"
public class Dog extends Serializable{ //attributes here... }
public class Cat extends Serializable{ //attributes here... }
the service interface will more likely look like this :
public interface Services<T> {
List<T> getAllRecords();
T getRecordById(int id);
T insertRecord(T animal);
// etc
}
and the repository will be like this :
public interface GenericRepository<T> extends CrudRepository<T,Serializable>{ //....}
then we'll be able to implement the services such as this :
#Service
public class CatServiceImpl implements Services<Cat>
{
#Autowired
GenericRepository<Cat> repositoryCat;
//...
}
#Service
public class DogServiceImpl implements Services<Dog>
{
#Autowired
GenericRepository<Dog> repositoryDog;
//...
}
and so on..
the problem is in the controller how can the #AutoWired annotation differentiate between the implementations?
Any suggestions?

Related

Error when trying to make generic method in spring boot app

This is my code Service interface (which i am trying to generify):
#org.springframework.stereotype.Service
public interface Service<T extends Planning> {
List<T> get(Specification<T> spec, Sort sort);
//PagingResponse getOther(Specification<T> spec, HttpHeaders headers, Sort sort);
}
And I created another class that extends to Service class, here are my PlanningServiceImpl class :
#Data
#Service
public class PlanningServiceImpl implements PlanningService, com.qoze.meeting.services.Service<Planning> {
#Autowired
private PlanningRepositoryInterface planningRepository;
#Override
public Iterable<Planning> getAllPlannings() {
return planningRepository.findAll();
}
#Override
public List<Planning> get(Specification<Planning> spec, Sort sort){
return planningRepository.findAll(spec, sort);
}
}
My PlanningService interface :
public interface PlanningService{
Iterable<Planning> getAllPlannings();
}
First the compiler doesn't recognize the spec parameter given in parameter. Then I change to put the extends on T object.
But here with my service I only allowed to work with Planning objects, I wanted at the beginning to have a generic Service and use several objects. Can someone help to have a generic service in spring boot app?

Is it better to use aggregation over inheritance when creating a generic CRUD component?

I have a question. I have these classes:
public interface CRUDService<MODEL extends BaseModel<ID>,ID extends Serializable>
{
List<MODEL> findAll();
MODEL findById(ID id);
// + delete, save & update methods
}
public abstract class AbstractCRUDService<MODEL extends BaseModel<ID>,ID extends Serializable> implements CRUDService<MODEL,ID>
{
//overriding the CRUDService interface methods here.
}
Is it better to extend each service from AbstractCRUDService like this:
public class DefaultProductService extends AbstractCRUDService<ProductModel,Long> implements ProductService
{ //some methods here}
or should I remove abstract from AbstractCRUDService and inject this service in the DefaultProductService ?
public class DefaultProductService implements ProductService {
#Autowired
private CRUDService<ProductModel,Long> crudService;
// override "ProductService" methods here.
}
It depends on your requirement.
If all Model Types, need the same CRUD implementation, you can go with your 2nd approach: composition.
However, if different Model objects require different CRUD implementations, the inheritance would fit better. For example, for all ProductModels Del(obj) will remove the object from the DB table, however, for all OrderModels Del(obj) doesn't remove the data, instead, it does something else, throw an exception, for example.
Yes, it is. You need to prefer composition over inheritance
here a really good post to read about it
composition over inheritance

Is it possible to have a method signature be a subtype of the interface it implements?

Say I have an interface:
public interface IDto {
}
and a class that implements this interface:
public class UserProfileResponseDto implements IDto {
}
In another interface I have:
public interface ISortingController {
public List<IDto> findAll();
}
In my concrete controller I have:
public List<UserProfileResponseDto> findAll();
but its telling me that it must be
public List<IDto> findAll();
Is there a way that would allow public List<UserProfileResponseDto> findAll(); as it feels like it should be allowed since UserProfileResponseDto implements IDto. The reason I ask this question is because I feel that it gives more verbosity the the controller class, which would make it easier to maintain and operate with.
You need to declare a type parameter in your ISortingController like this:
public interface ISortingController<D extends IDto> {
public List<D> findAll();
}
and your controller implementation needs to say implements ISortingController< UserProfileResponseDto>.

Spring Dependency Injection with Generic Types

There exist following classes
class Entity{
}
class Dto{
}
public abstract class BaseMapper<E extends Entity, D extends Dto>{
}
And several sepcific implementation of mappers like:
FooMapper extends BaseMapper<Foo, FooDto>{
}
FeeMapper extends BaseMapper<Fee, FeeDto>{
}
No I want to integrate some "Wrapper" which does a bit more than normal mapping of the data, because I got a new concept/issue
#Component
public final class RevMapper<ENTITY extends Entity, DTO extends Dto> {
private BaseMapper<ENTITY, DTO> baseMapper;
#Autowired
public <MAPPER extends BaseMapper<ENTITY, DTO>> RevMapper(MAPPER mapper) {
this.baseMapper = mapper;
}
public List<RevDto<DTO>> toDto(final List<Rev<ENTITY>> revList) {
for(Rev<ENTITY> rev: revList){
...
baseMapper.toDto(rev.getEntity(), true);
}
...
}
}
And include it in my service like:
#Autowired
private RevMapper<Foo, FooDto> fooRevMapper;
The problem now is:
Parameter 0 of constructor in com.test.package.RevMapper required a single bean, but 2 were found:
- FooMapper
- FeeMapper
Spring doesn't know which to take. And yeah what I know is about the type erasure in generics. So basically after compile the application just know that there is a
RevMapper<Entity,Dto>
but not which type it is specifically. How could I tell Spring to insert the right component, or how would you handle this problem. I do not want to write the same lines of code for each type of Mapper....
The solution I can think of is not as time consuming than creating many many subclasses.
First make the RevMapper not a #Component and then create a class like follows:
#Configuration
public final class Mappers{
private final FooMapper fooMapper;
private final FeeMapper feeMapper;
#Autowired
public Mappers(FooMapper fooMapper, FeeMapper feeMapper){
this.fooMapper = fooMapper;
this.feeMapper = feeMapper;
}
#Bean
public RevMapper<Foo, FooDto> fooRevMapper(){
return new RevMapper(fooMapper);
}
#Bean
public RevMapper<Fee, FeeDto> feeRevMapper(){
return new RevMapper(feeMapper);
}
}
It's no more than just creating a method for every different RevMapper you want to provide.

Spring data couchbase documents java classes inheritance

My problem is, that spring data couchbase doesn't search for subclasses of searched class. For example:
Model:
#Document
class A {
#Id
String id
}
#Document
class B extends A {}
And repository:
public interface ARepository extends PagingAndSortingRepository<A, String>{
Page<A> findAll(Pageable pageable);
}
Spring data couchbase generate query, that has in where condition
_class="com.example.model.A"
But I want in this query search B documents too. Is some way, how can I do this? When I write own query, I must defining order, limit and offset in query and Pageable is not used. But I want use Pageable.
Consider generic interface based on inheritance.
Firstly create super class:
#Inheritance
public abstract class SuperClass{
#Id
private int id;
}
Then create your subclasses:
public class A extends SuperClass { /* ... */ }
public class B extends SuperClass { /* ... */ }
Create base repository:
#NoRepositoryBean
public interface SuperClassBaseRepository<T extends SuperClass>
extends PagingAndSortingRepository<T, Integer> {
public T findAll();
}
And then create SuperClass repository basing on base repo:
#Transactional
public interface SuperClassRepository extends SuperClassBaseRepository<SuperClass> { /* ... */ }
#Transactional
public interface ARepository extends SuperClassBaseRepository<A> { /* ... */ }
#Transactional
public interface BRepository extends SuperClassBaseRepository<B> { /* ... */ }
SuperClassRepository findAll() will search all A and B classes
We managed to make this work on Spring Data Couchbase 3.2.12. Here's what we did:
We figured out that mappers for each type were only being created if a repository existed for that type, so, besides our superclass repository...
public interface ARepository extends PagingAndSortingRepository<A, String> {
Page<A> findAll(Pageable pageable);
}
We created an empty repository for each of the subtypes such as:
public interface BRepository extends PagingAndSortingRepository<B, String>{
// No methods
}
The presence of this second repo warranted the existence of an appropriate mapper for B, so when findAll (or other methods) are invoked in ARepository, the mapper for each subclass is present. Having done this, we were able to get a list of A that were actually B instances.
Hope this helps and nobody has to lose any more time on this. :)

Categories

Resources