Spring Data REST - Override repository findAll without creating /search/findAll URL - java

Is there any way to prevent Spring Data REST from creating a /search URLs for overridden repository methods?
For example the following code results in a /search/findAll URL being generated which duplicates the functionality of the collection resource:
public interface EmployeeRepository extends CrudRepository<Employee, Long>
{
#Override
#Query("SELECT e FROM Empolyee e")
Iterable<Employee> findAll();
}
This is only a cosmetic issue when overriding a single method but if you attempt to override multiple methods with the same function name and different parameters, for example both findAll methods in PagingAndSortingRepository then spring throws an exception because it's attempting to map 2 functions to the same path.
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>
{
#Override
#Query("SELECT e FROM Employee e")
Iterable<Employee> findAll();
#Override
#Query("SELECT e FROM Employee e")
Iterable<Employee> findAll(Sort sort);
#Override
#Query("SELECT e FROM Employee e")
Page<Employee> findAll(Pageable pageable);
}
Results in:
java.lang.IllegalStateException: Ambiguous search mapping detected. Both public abstract java.lang.Iterable uk.co.essl.roster.entity.employee.EmployeeRepository.findAll(org.springframework.data.domain.Sort) and public abstract java.lang.Iterable uk.co.essl.roster.entity.employee.EmployeeRepository.findAll() are mapped to /findAll! Tweak configuration to get to unambiguous paths!
at org.springframework.data.rest.core.mapping.SearchResourceMappings.<init>(SearchResourceMappings.java:60)
at org.springframework.data.rest.core.mapping.RepositoryResourceMappings.getSearchResourceMappings(RepositoryResourceMappings.java:128)
at springfox.documentation.spring.data.rest.EntityContext.searchMappings(EntityContext.java:107)
...

Is there any way to prevent Spring Data REST from creating a /search URLs for overridden repository methods?
I found following trick to solve this issue:
#Override
default Page<Employee> findAll(Pageable pageable) {
return findBy(pageable);
}
#RestResource(exported = false)
Page<Employee> findBy(Pageable pageable);
More other this trick allows you to set default sort order for 'get all records' request:
#Override
default Page<Employee> findAll(Pageable p) {
if (p.getSort() == null) {
// The default sort order
return findBy(new PageRequest(p.getPageNumber(), p.getPageSize(), Sort.Direction.DESC, "myField"));
}
return findBy(pageable);
}
Enjoy! ))
#RestResource(exported=false) just for overridden method will not help 'cause this blocks GET 'all records' request (

#RestResource(exported = false)

Related

MongoRepository same methods with diferent #Query

Using spring data mongo repository class, how can I do this? I need the same method twice but in one I need to exclude a field.
public interface Person extends MongoRepository<Person, String>{
Optional<Person> findById(String id);
#Query(fields="{ 'company': 0 }")
Optional<Person> findById(String id);
}
This doesn't work because I can't have the same method twice, is there a way to do it?
The problem arises when you want to call the method. It would be ambiguous which method is being called.
If you want to use method overloading to have a same name for both of your methods, it is only possible if they have different parameters.
here is an example:
public interface Person extends MongoRepository<Person, String>{
Optional<Person> findById(String id);
#Query(fields="{ 'company': 0 }")
Optional<Person> findById(String id, Boolean exclude);
}

Secure method of spring data rest repository

I am currently developping a REST API server based on Spring Boot. Thanks to Spring Data Rest, the 10-ish entities can easily have their own controller via a simple repository (#RepositoryRestResource plus JpaRepository and JpaSpecificationExecutor). Now i need to integrate the security control with #PreAuthorize.
The question here is which method should I put the annotation on to restrain GET / POST / etc. ?
For example, if I limit the permission of delete, does it affect similarly on deleteById, deleteInBatch, deleteAll? I see in the documentation the annotation of exported is put on deleteById and delete without any further explanation, which confuses me.
For example, if I limit the permission of delete, does it affect similarly on deleteById, deleteInBatch, deleteAll?
To the best of my knowledge: no. Check this sample code where searches are authorized, but deletion is strictly limited to admins only:
public interface RecordRepository<T extends Record> extends MongoRepository<T, String> {
// paginated queries
#RestResource(path = "names", rel = "name")
public Page<T> findByName(#Param("name") String name, Pageable pageable);
#RestResource(path = "types", rel = "types")
public Page<T> findByTypeIn(#Param("type") List<String> types, Pageable pageable);
// restrict delete operations to administrators only
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteById(String id);
#PreAuthorize("hasRole('ADMIN')")
#Override
void delete(T entity);
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteAll(Iterable<? extends T> records);
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteAll();
}
That being said, if your purpose is to restrict deletion to admins only, you can extend WebSecurityConfigurerAdapter and configure it to block all http DELETE requests:
public class WebSecurityBaseConfiguration extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.DELETE).hasRole("ADMIN");
}
}
Note that this is a quick and dirty copy paste that may not work out of the box (you will probably need to configure a role hierarchy).

How to create custom Spring Data JPA find method with my own property, specification and pageable?

I'd like to create my own custom Spring Data JPA find method that takes Integer, Specification and Pageable.
I've tried creating method like
Page<Student> findAllByGroupId(Integer id, Specification<Student> specification, Pageable pageable);
But it doesn't work.
User Repository
#Repository
public interface UserRepository<T extends User> extends PagingAndSortingRepository<T, Integer>,
JpaSpecificationExecutor<T> {
}
Student Repository
#Repository
public interface StudentRepository extends UserRepository<Student>{
Page<Student> findAllByGroupId(Integer id, Specification<Student> specification, Pageable pageable);
}
Service
#Override
public Page<Student> getGroupStudents(Integer id, StudentQuery studentQuery, Pageable pageable) {
Specification<Student> specification =
studentSpecification.getSpecification(studentQuery);
return studentRepository.findAllByGroupId(id, specification, pageable);
}
When I try this I get
java.lang.IllegalArgumentException: At least 2 parameter(s) provided but only 1 parameter(s) present in query.
Is there any way to create custom find method that takes Integer, Specification and Pageable?

Spring Data LDAP using Pageable is it possible?

I use spring Data LDAP, I want return all user but by page. findAll work but return all user.
I try user Page<UserLdap> findAll(Pageable pageable); but I have tise error:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'userLdapRepository':
Invocation of init method failed;
nested exception is org.springframework.data.mapping.PropertyReferenceException:
No property findAll found for type UserLdap!
full code:
public interface UserLdapRepository extends LdapRepository<UserLdap> {
Set<UserLdap> findAll();
Page<UserLdap> findAll(Pageable pageable);
}
I try add extends PagingAndSortingRepository<UserLdap, Name> but I have the same error.
full code:
public interface UserLdapRepository extends PagingAndSortingRepository<UserLdap, Name>, LdapRepository<UserLdap> {
Set<UserLdap> findAll();
Page<UserLdap> findAll(Pageable pageable);
}
Is it possible using Pageable with Spring Data LDAP please?
EDIT:
I find this code in Spring Data ldap:
public Page<T> findAll(Predicate predicate, Pageable pageable) { ...
What is it a predicate please? If you have a sample, I'm happy :)
it is not possible:
UnsupportedOperationException()
#Override
public Page<T> findAll(Predicate predicate, Pageable pageable) {
throw new UnsupportedOperationException();
}
"Due to specifics of the LDAP protocol, paging and sorting are not supported for Spring LDAP repositories."
See more in https://docs.spring.io/spring-data/ldap/docs/current/reference/html/#ldap.repositories

Pagination with spring boot usiing jpa

How can I implement a method that return a page of objects using JpaRepository and not PagingAndSortingRepository ?
My repository
public interface GroupRepository extends JpaRepository<Group, Long> {
#Query(value = "SELECT g FROM Group")
Page<Group> listAllByPage(Pageable pageable);
}
My service implementation:
#Override
public
Page<Group> findGroupesByPagination(Pageable pageable) {
return groupeRepository.listAllByPage(pageable);
}
My rest Controller method:
#RequestMapping(value="/groups", method = RequestMethod.GET)
public #ResponseBody Page<Group> list( Pageable pageable){
Page<Group> groupes = groupeServiceImpl.findGroupesByPagination(pageable);
return groupes;
}
Finally I got this error:
Error creating bean with name 'groupServiceImpl': Unsatisfied
dependency expressed through field 'groupeRepository'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'groupRepository': Invocation of init
method failed; nested exception is java.lang.IllegalArgumentException:
Validation failed for query for method public abstract
org.springframework.data.domain.Page
rimtrack.org.repository.GroupRepository.listAllByPage(org.springframework.data.domain.Pageable)!
The query can be defined by an annotation somewhere or declared by other means. Consult the documentation of the specific store to find available options for that store. If the repository infrastructure does not find a declared query for the method at bootstrap time, it fails.
You should using Spring Data Jpa method. Reference
Page<T> findAll(Pageable pageable);
Please change repository class.
Exam:
public interface GroupRepository extends JpaRepository<Group, Long> {
Page<Group> findAlll(Pageable pageable);
}

Categories