I have a problem with my REST app. Here is the git link to ease your burden: https://github.com/TheNiceGuy123/AstonishingBackEnd
Here is the raw code also:
Classes posted in order:
Employee Controller:
package com.example.csmartbackend.controller; import com.example.csmartbackend.model.Employee; import com.example.csmartbackend.modeldto.EmployeeDto; import com.example.csmartbackend.service.EmployeeService; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; import java.util.UUID; @RestController @RequestMapping("employee") @RequiredArgsConstructor public class EmployeeController { private final EmployeeService employeeService; @GetMapping("find/{Cnp}") public ResponseEntity<Employee> findByCNP(@PathVariable("Cnp") String Cnp) { Employee employee = employeeService.findByCnp(Cnp); HttpHeaders header = new HttpHeaders(); header.add("Desc","Getting employee by id."); return ResponseEntity.status(HttpStatus.OK).headers(header).body(employee); } }
Employee Service:
package com.example.csmartbackend.service; import com.example.csmartbackend.mapper.EmployeeMapper; import com.example.csmartbackend.model.Employee; import com.example.csmartbackend.modeldto.EmployeeDto; import com.example.csmartbackend.repository.EmployeeRepository; import exception.general.TargetNotFoundException; import exception.requestsexceptions.CNPNotFoundException; import exception.requestsexceptions.EmployeeNotFoundException; import exception.requestsexceptions.InvalidIdException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.util.List; import java.util.Optional; import java.util.UUID; @Service @RequiredArgsConstructor @Transactional public class EmployeeService implements EmployeeServiceImpl { private final EmployeeRepository employeeRepository; private final ContractService contractService; private final AdressService adressService; public Employee findByCnp(String Cnp) throws CNPNotFoundException { Optional<Employee> employeeOptional = Optional.ofNullable(employeeRepository.findByCnp(Cnp)); if(employeeOptional.isPresent()) return employeeOptional.get(); else throw new CNPNotFoundException("No employee found."); } }
Global Exception Handler:
package exception.requestsexceptions; import org.springframework.beans.TypeMismatchException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingPathVariableException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @Override protected ResponseEntity<Object> handleHttpRequestMethodNotSupported (HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Request method not supported."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @Override protected ResponseEntity<Object> handleHttpMediaTypeNotSupported (HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Media method not supported."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @Override protected ResponseEntity<Object> handleMissingPathVariable (MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Path variable is missing."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @Override protected ResponseEntity<Object> handleMissingServletRequestParameter (MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Request parameter is missing."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @Override protected ResponseEntity<Object> handleTypeMismatch (TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Mismatch of type."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @Override protected ResponseEntity<Object> handleHttpMessageNotReadable (HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Request body is not readable."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now()); return ResponseEntity.status(status).body(apiErrorModel); } @ExceptionHandler(EmployeeNotFoundException.class) public ResponseEntity<Object> handleEmployeeNotFoundException(EmployeeNotFoundException ex) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Employee not found."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, HttpStatus.BAD_REQUEST, LocalDateTime.now()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(apiErrorModel); } @ExceptionHandler(CNPNotFoundException.class) public ResponseEntity<Object> handleInvalidCNPException(CNPNotFoundException ex) { String message = ex.getMessage(); List<String> details = new ArrayList<>(); details.add("Employee with the given CNP not found."); ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, HttpStatus.NOT_FOUND, LocalDateTime.now()); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(apiErrorModel); } }
CNPNotFoundException class:
package exception.requestsexceptions; public class CNPNotFoundException extends RuntimeException { public CNPNotFoundException(String message) { super(message); } }
ApiErrorModel class:
package exception.requestsexceptions; import lombok.*; import org.springframework.http.HttpStatus; import java.time.LocalDateTime; import java.util.List; @Setter @Getter @NoArgsConstructor @AllArgsConstructor @ToString public class ApiErrorModel { String message; List<String> details; HttpStatus status; LocalDateTime timestamp; }
I want to give some relevant informations to the user like in the second picture but in postman everything remains at the default level to call it like that, like my code from the handler is not even there. Is any logic or annotation that I miss?
This is how it looks on my side
This is how it should look like
Thank you for your time!
Advertisement
Answer
Problem is when a class is annotated with the @SpringBootApplication
without any attribute SpringBoot only scans the package and its subpackages where the class itself is located.
In your case it means SpringBoot only looking for any Spring components under com.example.csmartbackend
package while you put GlobalExceptionHandler
class in exception.requestsexception
s package.
To fix it you have two choices:
- put the
exception
package under com.example.csmartbackend, so it would becom.example.csmartbackend.exception.requestsexception.GlobalExceptionHandler
- tell spring to scan the
exception
package as well, either by usingscanBasePackageClasses
orscanBasePackages
attribute, e.g@SpringBootApplication(scanBasePackageClasses = {CSmartBackEndApplication.class, GlobalExceptionHandler.class})