Cannot use findAll(Specifications, Pageable) method for JpaSpecificationExecutor repository. I have the repository interface as:
package com.task.task.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.task.task.domain.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>, JpaSpecificationExecutor<Employee> {
}
Whenever I am calling employeeRepository.findAll(specifications, pageable); This error is thrown:
"error": "Internal Server Error",
"exception": "org.springframework.beans.BeanInstantiationException",
"message": "Failed to instantiate [org.springframework.data.jpa.domain.Specifications]: No default constructor found;
nested exception is java.lang.NoSuchMethodException: org.springframework.data.jpa.domain.Specifications.<init>()",
"path": "/api/task/employee"
This is stacktrace:
2018-01-17 14:41:29.816 ERROR 12132 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.jpa.domain.Specifications]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.data.jpa.domain.Specifications.<init>()] with root cause
java.lang.NoSuchMethodException: org.springframework.data.jpa.domain.Specifications.<init>()
at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_144]
at java.lang.Class.getDeclaredConstructor(Class.java:2178) ~[na:1.8.0_144]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:102) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
Full code : https://github.com/SanketKD/SpecificationExecutor
Entity:
@Entity
@Table(name = "emp111")
public class Employee {
@Id
@Column(name = "employee_id")
private Long employeeId;
@Column(name = "ename", length = 20)
private String ename;
@Column(name = "hire_date")
private Date hireDate;
@Column(name = "salary")
private Long salary;
@Column(name = "skills", length = 30)
private String skills;
// getters setters
Service:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.stereotype.Service;
import com.task.task.domain.Employee;
import com.task.task.repository.EmployeeRepository;
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
@Autowired
public EmployeeService(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public Employee getEmployee(Long employeeId) {
return employeeRepository.findOne(employeeId);
}
public Page<Employee> getEmployees(Specifications<Employee> specifications, Pageable pageable) {
return employeeRepository.findAll(specifications, pageable);
}
}
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.task.task.domain.Employee;
import com.task.task.service.EmployeeService;
@RestController
@RequestMapping("api/task/employee")
public class EmployeeController {
private final EmployeeService employeeService;
@Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@RequestMapping(method = RequestMethod.GET, path = "/{employeeId:[0-9]\\d*}")
public Employee getEmployee(@PathVariable Long employeeId) {
return this.employeeService.getEmployee(employeeId);
}
@RequestMapping(method = RequestMethod.GET)
public Page<Employee> getEmployees(Specifications<Employee> specifications, Pageable pageable) {
return this.employeeService.getEmployees(specifications, pageable);
}
}
Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.task.task.domain.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>, JpaSpecificationExecutor<Employee> {
}
The exception you get is not related to the repository, it's because you mapped Specification<Employee> in your controller. This is not possible because Spring has no idea how to "parse" the incoming request to Specification<Employee>. It will try to construct the Specification by calling the default constructor, but since there is no default constructor, it throws an exception in stead.
Rather than mapping it in your controller, you need to use a proper request body (or parameters) and create the Specification either in your controller, or your service.
Using Spring boot 2.x.x, you can do that with:
@RequestMapping(method = RequestMethod.GET)
public Page<Employee> getEmployees(
// Just plain parameters
@RequestParam String name,
@RequestParam int page,
@ResuestParam int limit) {
// Creating the specification
Specification<Employee> spec = Specification.where(EmployeeSpecs.employeeName(name));
// Creating the Pageable as well
Pageable pageable = PageRequest.of(page, limit);
return this.employeeService.getEmployees(specifications, pageable);
}
Using Spring boot 1.x.x, Specification.where() is called Specifications.where(). Additionally, the PageRequest.of(..) static method doesn't exist, and you should use the new PageRequest(..) constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With