I have created a webapp serving somewhat like a REST catalog of employees stored in embedded database, but something goes wrong. I have an UnsatisfiedDependencyException: Error creating bean with name
'employeeController': Unsatisfied dependency expressed through field 'employeeService': Error creating bean with name 'employeeServiceImpl': Unsatisfied dependency expressed through field 'employeeRepository': Error creating bean with name 'employeeRepository' defined in com.springemployeecatalog.repository.EmployeeRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Not a managed type: class com.springemployeecatalog.entity.Employee.
What am I doing wrong?
Endpoints (all serves GET requests) should be:
/employees
- list all employees. Supports paging*.
/employees/{employee_id}
- single employee. If parameter named full_chain exists and is set to true then full manager chain should be written (include employee`s manager, manager of manager, manager of manager of manager and so on up to the organization head).
/employees/by_manager/{managerId}
- list employees who subordinates to the manager. No transitivity. Supports paging*.
/employees/by_department/{departmentId or departmentName}
- list employees who is working in the department. Supports paging*.
Entity: Employee class
package com.springemployeecatalog.entity;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.IOException;
import java.io.StringWriter;
import java.time.LocalDate;
import java.util.List;
@Entity
@NoArgsConstructor
@Table(name ="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
private Integer id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "fullName")
private FullName fullName;
@Enumerated(EnumType.ORDINAL)
@Column(name = "position")
private Position position;
@ManyToOne(cascade = {CascadeType.PERSIST })
@JoinColumn(name = "manager_id")
private Employee manager;
@Column(name = "hired")
private LocalDate hired;
@Column(name = "salary")
private Double salary;
@ManyToOne(cascade ={CascadeType.ALL})
@JoinColumn(name = "department_id")
private Department department;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "manager_id", referencedColumnName = "emp_id")
private List<Employee> employeeList;
// constructors, getters, setters ...
Department class
package com.springemployeecatalog.entity;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
@Entity
@NoArgsConstructor
@Table(name = "department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "dep_id")
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "location")
private String location;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "department_id", referencedColumnName = "dep_id" )
private List <Employee> employeeList;
// constructors, getters, setters ...
FullName class
package com.springemployeecatalog.entity;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import javax.persistence.*;
@Embeddable
public class FullName {
@Column(name = "firstname")
private String firstName;
@Column(name = "lastname")
private String lastName;
@Column(name = "middlename")
private String middleName;
@OneToOne(mappedBy = "fullNAme", cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
private Employee employee;
// constructors, getters, setters ...
Position enum package com.springemployeecatalog.entity;
public enum Position {
PRESIDENT,
MANAGER,
ANALYST,
CLERK,
SALESMAN
}
Controller:
package com.springemployeecatalog.controller;
import com.springemployeecatalog.entity.Employee;
import com.springemployeecatalog.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/")
public String homePage() {
return "Welcome to the Employee Catalog!";
}
@GetMapping("/employees")
public List<Employee> showAllEmployees(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id") String sort) {
return employeeService.getAllEmployees(page, size, sort);
}
@GetMapping("/employees/{id}")
public Employee findEmployee(@PathVariable Integer id,
@RequestParam(defaultValue = "false") boolean fullChain) {
return employeeService.getEmployee(id, fullChain);
}
@GetMapping("/employees/by_manager/{managerId}")
public List<Employee> findEmployeesByManager(@PathVariable Integer managerId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id") String sort){
return employeeService.getEmployeesByManager(managerId, page, size, sort);
}
@GetMapping("/employees/by_department/{departmentId}")
public List<Employee> findEmployeesByDepartment(@PathVariable Integer departmentId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id") String sort) {
return employeeService.getEmployeesByDepartment(departmentId, page, size, sort);
}
}
Repository:
package com.springemployeecatalog.repository;
import com.springemployeecatalog.entity.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DepartmentRepository extends JpaRepository<Department, Integer> {
}
package com.springemployeecatalog.repository;
import com.springemployeecatalog.entity.Department;
import com.springemployeecatalog.entity.Employee;
import org.springframework.data.entity.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface EmployeeRepository extends JpaRepository <Employee, Integer> {
List<Employee> findEmployeesByManager(Employee manager, Pageable pageable);
List<Employee> findEmployeesByDepartment(Department department, Pageable pageable);
}
Service:
package com.springemployeecatalog.service;
import com.springemployeecatalog.entity.Employee;
import java.util.List;
public interface EmployeeService {
List<Employee> getAllEmployees(int page, int size, String sort);
Employee getEmployee(Integer id, boolean fullChain);
List<Employee> getEmployeesByManager(Integer managerId, int page, int size, String sort);
List<Employee> getEmployeesByDepartment(Integer departmentId, int page, int size, String sort);
}
package com.springemployeecatalog.service;
import com.springemployeecatalog.entity.Department;
import com.springemployeecatalog.entity.Employee;
import com.springemployeecatalog.repository.DepartmentRepository;
import com.springemployeecatalog.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class EmployeeServiceImpl implements EmployeeService{
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private DepartmentRepository departmentRepository;
@Override
public List<Employee> getAllEmployees(int page, int size, String sort) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sort));
Page<Employee> employeePage = employeeRepository.findAll(pageable);
System.out.println("Отримано " + employeePage.getTotalElements() + " записів");
return employeePage != null ? employeePage.getContent() : Collections.emptyList();
}
@Override
public Employee getEmployee(Integer id, boolean fullChain) {
Employee employee = employeeRepository.findById(id).orElse(null);
List<Employee> managerChain = new ArrayList<>();
if (fullChain && employee != null) {
Employee manager = employee.getManager();
while (manager != null) {
managerChain.add(manager);
manager = manager.getManager();
}
}
Map<String, Object> response = new HashMap<>();
response.put("employee", employee);
response.put("managerChain", managerChain);
return employee;
}
@Override
public List<Employee> getEmployeesByManager(Integer managerId, int page, int size, String sort) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sort));
Employee manager = employeeRepository.findById(managerId).orElse(null);
if (manager != null) {
return employeeRepository.findEmployeesByManager(manager, pageable);
}
return Collections.emptyList();
}
@Override
public List<Employee> getEmployeesByDepartment(Integer departmentId, int page, int size, String sort) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sort));
Department department = departmentRepository.findById(departmentId).orElse(null);
if (department != null) {
return employeeRepository.findEmployeesByDepartment(department, pageable);
}
return Collections.emptyList();
}
}
This is application properties:
server.port=8080
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=
spring.jpa.show-sql=true
pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring</groupId>
<artifactId>employees-catalogue</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>19</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
I think with Spring 3, I've seen some usage of annotations from Jakarta
(ex: jakarta.persistence.Entity
) instead of javax.persistence
to resolve this error.
Can you test with Jakarta annotations instead of javax.persistence
and see if it resolves? You will need to replace Entity, Id, and perhaps more.