JpaSpecificationExecutor<T>存储库无法使用findAll(Specifications<T>, Pageable)方法?

4

无法在JpaSpecificationExecutor存储库中使用findAll(Specifications,Pageable)方法。 我有以下存储库接口:

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> {
}

每当我调用employeeRepository.findAll(specifications, pageable);时,就会抛出这个错误:
    "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"

这是堆栈跟踪信息:

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]

完整代码:https://github.com/SanketKD/SpecificationExecutor

实体:

@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

服务:

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);
  }
}

控制器:

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);
  }
}

代码仓库:

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> {
}

在你的实体员工中添加默认构造函数。 - Oomph Fortuity
添加你的依赖项。 - M. Deinum
@SanketKD - 你能分享一下您的代码,或者Specifications <Employee>规范或者EmployeeSpecs.employeeName(name)吗? - PAA
1个回答

2
您得到的异常与存储库无关,而是因为您在控制器中映射了 Specification<Employee>。这是不可能的,因为Spring不知道如何"解析"传入请求到Specification<Employee>。它将尝试通过调用默认构造函数来构造Specification,但由于没有默认构造函数,它会抛出异常。
您需要在控制器中使用适当的请求正文(或参数),并在控制器或服务中创建 Specification,而非在控制器中进行映射。
使用Spring Boot 2.x.x,您可以使用以下方法实现:
@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);
}

使用Spring Boot 1.x.x,调用Specification.where()的方法应该改为Specifications.where()。此外,PageRequest.of(..)静态方法不存在,应该使用new PageRequest(..)构造函数。

请问您能分享一下导入语句吗?因为Specification已经被弃用了。 - PAA
@PAA Specification 本身并没有被弃用。但是 Specifications.where() 已经被弃用,并且已经移动到 Specification.where()。我已经将我的代码更改为与 Spring Boot 2.x.x 兼容。 - g00glen00b
在我的情况下,我收到错误消息 Specification 类型中的 where(Specification<T>) 方法不适用于参数 (Specification<Employee>)。我在这里提出了问题:https://stackoverflow.com/questions/57131227/caused-by-java-lang-illegalargumentexception-failed-to-create-query-for-method - PAA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接