I have created an Employee Service Implementation class along with a Employee Service interface as a part of my Springboot learning. I have data in my database table, but I am getting the following error
java.lang.NullPointerException: Cannot invoke "com.example.demo.implementation.EmployeeServiceImpl.listEmployees(int)" because "this.employeeService" is null
Here is my Service Implementation class
import com.example.demo.model.Employee;
import com.example.demo.repository.EmployeeRepository;
import com.example.demo.service.EmployeeService;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.util.Collection;
import java.util.Random;
@RequiredArgsConstructor
@Service
@Transactional
@Slf4j
public class EmployeeServiceImpl implements EmployeeService {
private final EmployeeRepository employeeRepository;
@Override
public Employee createEmployee(Employee employee) {
log.info("Saving new employee: {}", employee.getEmployeeId());
employee.setImageUrl(setEmployeeImageUrl());
return employeeRepository.save(employee);
}
@Override
public Collection<Employee> listEmployees(int limit) {
log.info("Fetching all employees");
return employeeRepository.findAll(PageRequest.of(0, limit)).toList();
}
@Override
public Employee getEmployee(String employeeId) {
log.info("Fetching employee by ID: {}", employeeId);
return employeeRepository.findByEmployeeId(employeeId);
}
@Override
public Employee updateEmployee(Employee employee) {
log.info("Updating employee {}", employee.getEmployeeId());
return employeeRepository.save(employee);
}
@Override
public Boolean deleteEmployee(String employeeId) {
log.info("Deleting employee {}", employeeId);
employeeRepository.deleteById(employeeId);
return Boolean.TRUE;
}
private String setEmployeeImageUrl() {
String[] imageNames = {"face1.png"};
return ServletUriComponentsBuilder.fromCurrentContextPath().path("/server/image/" + imageNames[new Random().nextInt(1)]).toUriString();
}
}
And here is my Employee Service interface
import com.example.demo.model.Employee;
import org.springframework.stereotype.Service;
import java.util.Collection;
@Service
public interface EmployeeService {
Employee createEmployee(Employee employee);
Collection<Employee> listEmployees(int limit);
Employee getEmployee(String employeeId);
Employee updateEmployee(Employee employee);
Boolean deleteEmployee(String employeeId);
}
Here is my controller
import com.example.demo.implementation.EmployeeServiceImpl;
import com.example.demo.model.Employee;
import com.example.demo.model.Response;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import static java.time.LocalDateTime.now;
import static java.util.Map.*;
import static java.util.Map.of;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;
@RestController
@RequestMapping("/employee")
@RequiredArgsConstructor
public class EmployeeController {
private EmployeeServiceImpl employeeService;
// Return the list of employees
// Return a response entity of OK with a body of
// builder method of model Response
// with current timestamp LocalDateTime.now()
// and then map the data with the key employee and the value returned by listEmployees of employeeService
// with embeded success message, status, and statusCode. Then build the entire package
@GetMapping("/list")
public ResponseEntity<Response> getEmployees() {
return ResponseEntity.ok(
Response.builder()
.timestamp(now())
.data(of("employees", employeeService.listEmployees(30)))
.message("Employee retrieved")
.status(OK)
.statusCode(OK.value())
.build()
);
}
// save an employee
@PostMapping("/save")
public ResponseEntity<Response> saveEmployee(@RequestBody @Valid Employee employee) {
return ResponseEntity.ok(
Response.builder()
.timestamp(now())
.data(of("employee", employeeService.createEmployee(employee)))
.message("Employee created")
.status(CREATED)
.statusCode(CREATED.value())
.build()
);
}
// Return a specific employee with employeeID
@GetMapping("/getemployee/{employeeId}")
public ResponseEntity<Response> getEmployee(@PathVariable("employeeId") String employeeId) {
return ResponseEntity.ok(
Response.builder()
.timestamp(now())
.data(of("employee", employeeService.getEmployee(employeeId)))
.message("Employee retrieved")
.status(OK)
.statusCode(OK.value())
.build()
);
}
@DeleteMapping("/deleteemployee/{employeeId}")
public ResponseEntity<Response> deleteEmployee(@PathVariable @Valid String employeeId) {
return ResponseEntity.ok(
Response.builder()
.timestamp(now())
.data(of("deleted", employeeService.deleteEmployee(employeeId)))
.message("Employee deleted")
.status(OK)
.statusCode(OK.value())
.build()
);
}
}
Appreciate any help here, thank you!
>Solution :
The problem originates where you use EmployeeServiceImpl.listEmployees(int). It is probably in one of controller classes where you call the service method.
As a reason for the error, I guess that service implementation is not properly injected to EmployeeService instance in the controller. As it could not be instantiated correctly, it is null and referencing the null object results in the NPE you mention.
Solution:
- Add final keyword to EmployeeService employeeService; line in the controller