Error when trying to make generic method in spring boot app - java

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?

Related

Not able to override Spring data Pageable - Spring Neo4j

I need to override the Pageable class provided by spring data and then override the findAll method provided by the SimpleNeo4jRepository.
But on doing so, I am getting an error on server startup
Caused by: java.lang.IllegalArgumentException: Paging query needs to have a Pageable parameter! Offending method public abstract com.app.backend.repository.pagination.AppPage com.app.backend.repository.BaseRepository.findAll(com.app.backend.repository.pagination.AppPageRequest)
at org.springframework.util.Assert.isTrue(Assert.java:116) ~[spring-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.data.repository.query.QueryMethod.<init>(QueryMethod.java:99) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
at org.springframework.data.neo4j.repository.query.GraphQueryMethod.<init>(GraphQueryMethod.java:41) ~[spring-data-neo4j-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.neo4j.repository.query.GraphQueryLookupStrategy.resolveQuery(GraphQueryLookupStrategy.java:49) ~[spring-data-neo4j-5.0.9.RELEASE.jar:5.0.9.RELEASE]
Here is the code
public class AppPageRequest extends PageRequest implements Pageable {
private AppPageRequest(int page, int size, Sort sort) {
super(page - 1, size, sort);
}
public static AppPageRequest of(int page, int size) {
return of(page, size, Sort.unsorted());
}
public static AppPageRequest of(int page, int size, Sort sort) {
return new AppPageRequest(page, size, sort);
}
}
#NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends Neo4jRepository<T, ID> {
Page<T> findAll(AppPageRequest appPageRequest);
}
#NoRepositoryBean
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleNeo4jRepository<T, ID> implements BaseRepository<T, ID> {
public BaseRepositoryImpl(Class<T> domainClass, Session session) {
super(domainClass, session);
}
public Page<T> findAll(AppPageRequest appPageRequest) {
return super.findAll(appPageRequest);
}
}
assuming you want to make sure that no-one is able to call findAll and related with the default implementation of Pageable, there are two things you have to take care of:
You cannot override the signature of findAll and related by extending your BaseRepository from Neo4jRepository, the methods are not overwritten but overloaded and can be called as before.
To make Spring Data aware of the your custom repository implementation you have to specify the new base class when enabling Neo4j (or any other repository) (as described here).
With that in mind, here is a solution that works for us. Tested with Spring Boot 2.0.4, Spring Data Kay and OGM 3.1.0, running on Java 10. Find the complete solution in this Gist.
Keypoints:
Extend Spring Datas CrudRepository at max:
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
Page<T> findAll(AppPageRequest appPageRequest);
}
CrudRepository does not contain findAll, so your users cannot use it. Keep your BaseRepositoryImpl as is (see gist).
Make your domain repository extend BaseRepository and again not Neo4jRepository as such:
interface ThingRepository extends BaseRepository<ThingEntity, Long> {
}
Then the important step, make SDN aware of the new base implementation through #EnableNeo4jRepositories:
#SpringBootApplication
#EnableNeo4jRepositories(repositoryBaseClass = BaseRepositoryImpl.class)
public class CustomPagerequestApplication {
public static void main(String[] args) {
SpringApplication.run(CustomPagerequestApplication.class, args);
}
}
And then you're able to use your repo like this:
#Component
class ExampleUsage implements CommandLineRunner {
private final ThingRepository thingRepository;
public ExampleUsage(ThingRepository thingRepository) {
this.thingRepository = thingRepository;
}
#Override
public void run(String... args) {
var things = IntStream.iterate(1, i -> i <= 10, i -> i + 1)
.mapToObj(ThingEntity::new)
.collect(toList());
this.thingRepository.saveAll(things);
var page = this.thingRepository.findAll(AppPageRequest.of(1, 5));
page.stream().map(ThingEntity::getName).forEach(System.out::println);
}
}
Please let me know, if this helps. Again, here the link to the complete example:
Enforce a concrete implementation of Pageable for paged Queries with Spring Data (Neo4j)
It was a configuration miss. Mentioning BaseRepositoryImpl as the repository base class fixed the issue.
I changed
#EnableNeo4jRepositories
to
#EnableNeo4jRepositories(repositoryBaseClass = BaseRepositoryImpl.class)

How to implement custom method of CrudRepository in Spring boot 2.0?

I can find this question has been asked earlier. But neither the answer nor the documentation is working for me. I follow this doc.
I would like to add 2 custom interface to the repository. I must be doing something wrong in my code.
The compiler gives error:
Error:(18, 8) java: com.ma.home.service.BuyerPartyDetailsServiceImpl is not abstract and does not override abstract method deleteAll() in org.springframework.data.repository.CrudRepository.
Custom repository:
#Repository
public interface CustomBuyerPartyDeatilsDAO {
#Query("SELECT b FROM BuyerPartyDetails buyer WHERE LOWER(buyer.xmlFileName) = fileName")
public List<BuyerPartyDetails> listByfileName(String fileName);
#Query("SELECT b FROM BuyerPartyDetails buyer WHERE LOWER(buyer.buyerOrganisationName) = name")
public BuyerPartyDetails getByBuyerPartyByName(String name);
}
Repository:
#Repository
public interface BuyerPartyDetailsDAO2 extends
CrudRepository<BuyerPartyDetails, Long>, CustomBuyerPartyDeatilsDAO {
public List<BuyerPartyDetails> listByfileName(String fileName);
public BuyerPartyDetails getByBuyerPartyByName(String name);
}
Service:
#Service
public class BuyerPartyDetailsServiceImpl implements
BuyerPartyDetailsDAO2,
CustomBuyerPartyDeatilsDAO {
#Autowired
private BuyerPartyDetailsDAO2 buyerPartyDetailsDAO2;
public BuyerPartyDetailsServiceImpl() {
}
// more implementation removed.
.......
.......
}
If I provide the implementation for deleteAll(), it asks one by one all the CrudRepository methods such as save(), saveAll(), findById(), findAll(), etc.
So how can use CrudRepository already implemented methods?
To resolve this error
com.ma.home.service.BuyerPartyDetailsServiceImpl is not abstract and does not override abstract method deleteAll() in org.springframework.data.repository.CrudRepository
you have to override all abstract methods and provide implementation for them to make it functional.
If you don't need to implement them all then you have to inject DAO interfaces into services and let the services implement their own interfaces.
Spring will do the rest by providing suitable implementation of your interfaces that you should configure in the application context.

Spring Boot : generic Crudrepository interface and generic service interface

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?

How to force Spring Data to create query methods with entity runtime type?

I've got around 5 objects that I want to do similar things with.
I figured out that not to polute the code I will put a logic for those objects in one place.
public class MetaObjectController<T extends MetaObject> {
#Autowired
private final MetaObjectRepository<T> repository;
// generic logic
Here's how repository looks:
public interface MetaObjectRepository<T extends MetaObject> extends GraphRepository<T> {
T findByName(String name);
}
Now, I create concrete class which uses delegation:
public class ExperimentalController {
#Autowired
private final MetaObjectController<MetaCategory> metaController;
#RequestMapping(method = RequestMethod.POST)
public void add(#RequestBody MetaCategory toAdd) {
metaController.add(toAdd);
}
Now, when I look at the generated queries I see, that although instantiated correctly, repository puts MetaObject as an entity name instead of runtime type.
Is there a way to force the repository to use runtime type?
Please don't advise to put a #Query annnotation. That's not what I am looking for.
This is most probably due to type erasure: at runtime there is only the type constraint available which is MetaObject. If you want to use (via spring-data) the actually relevant subclass you will have to create explicit interfaces of the MetaObjectRepository like this:
public class Transmogrifier extends MetaObject
public interface MetaTransmogrifierRepository
extends MetaObjectRepository<Transmogrifier> {}

Partially implemented repository with Spring data Neo4j 4

I'm trying to partially implement a repository using the following structure:
public interface ExampleCustomRepository {
Iterable<Example> findExamplesByUserId(Long id);
}
#Repository
#Transactional
public class ExampleCustomRepositoryImpl implements ExampleCustomRepository {
#Autowired
private Neo4jTemplate template;
#Override
public Iterable<Example> findExamplesByUserId(final Long id) {
// implementation
}
}
public interface ExampleRepository extends GraphRepository<Example>, ExampleCustomRepository {
}
For some reason the RepositoryFactory wants to create a DerivedGraphRepositoryQuery for this implemented method, and fails:
org.springframework.data.mapping.PropertyReferenceException: No property userId found for type Example!
Is it even possible to partially implement a repository with SDN4? If it is, what am I doing wrong?
I overlooked the naming convention, which was explained here.
I had too rename ExampleCustomRepositoryImpl to ExampleRepositoryImpl.

Categories

Resources