Search code examples
javaspring-boothibernatespring-data-jpadto

JPA Query - no appropriate constructor in class error


I have an Employee entity class that has many columns. I want to get some columns from this class, therefore I have used dtos. I created a new BaseEmployee class and writed query in EmployeeRepository. But I get this error: "no appropriate constructor in class error" when I try to run app.

@Entity
@Table(name = "employees")
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "emp_no")
    private  int id;
    @Column(name = "birth_date")   
    private Date birthDate;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @Column(name = "gender")
    private char gender;
    @Column(name = "hire_date")  
    private Date hireDate;

    @OneToMany(mappedBy = "employees")
    private List<Title> titles; 

    @OneToMany(mappedBy = "employees")
    private List<Salary> salary;

    @OneToMany(mappedBy = "employee")
    private List<DeptEmp> departmentList;

   @OneToMany(mappedBy = "employee")
   private List<DeptManager> managerDepartment;

}

My dto class:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BaseEmployee {

    private  int id;
    private Date birthDate;
    private String firstName;
    private String lastName;
    private char gender;
    private Date hireDate;

}

Jpa Repository:

public interface EmployeeRepository extends JpaRepository<Employee,Integer> {
    
    List<Employee> getByFirstNameContains(String firstName);
    List<Employee> getByFirstNameStartsWith(String firstName);


    @Query("Select new dev.serhat.employeeapi.models.dtos.BaseEmployee"
    + "(e.id, e.birthDate, e.firstName, e.lastName, e.gender, e.hireDate) From Employee e WHERE e.id = :id")
    Optional<BaseEmployee> getBaseEmployeeById(int id);
    
    
}

Errors:

HH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
2022-02-20 16:33:42.533  INFO 24371 --- [  restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-02-20 16:33:42.559  INFO 24371 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-02-20 16:33:43.431 ERROR 24371 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        :  Unable to locate appropriate constructor on class [dev.serhat.employeeapi.models.dtos.BaseEmployee]. Expected arguments are: int, java.util.Date, java.lang.String, java.lang.String, char, java.util.Date
[cause=org.hibernate.PropertyNotFoundException: no appropriate constructor in class: dev.serhat.employeeapi.models.dtos.BaseEmployee]
2022-02-20 16:33:43.443 ERROR 24371 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        :  Unable to locate appropriate constructor on class [dev.serhat.employeeapi.models.dtos.BaseEmployee]. Expected arguments are: int, java.util.Date, java.lang.String, java.lang.String, char, java.util.Date
[cause=org.hibernate.PropertyNotFoundException: no appropriate constructor in class: dev.serhat.employeeapi.models.dtos.BaseEmployee]

org.hibernate.hql.internal.ast.DetailedSemanticException: Unable to locate appropriate constructor on class [dev.serhat.employeeapi.models.dtos.BaseEmployee]. Expected arguments are: int, java.util.Date, java.lang.String, java.lang.String, char, java.util.Date
        at org.hibernate.hql.internal.ast.tree.ConstructorNode.resolveConstructor(ConstructorNode.java:182) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]

Solution

  • The all-args constructor that Lombok generates calls for two arguments of type java.util.Date.

    When hibernate executes your jpql, it uses org.hibernate.type.TimestampType objects in the constructor and not java.util.Date objects. Of course no such constuctor was generated, hence the error.

    Here is a stack overflow discussion of how to deal with this situation: How to force Hibernate to return dates as java.util.Date instead of Timestamp?