Spring Can't recognise application.proerties file. Unable to display the configuration defines in property file - spring

I'm trying to display my custom message while handling the exception. But I'm getting no response in the Postman. Here is code snippet that I've used
So, Here is my controller class method
#GetMapping(value="/customers/{customerId}")
public ResponseEntity<Customer> getCustomerById(#PathVariable Integer customerId) throws Exception
{
try {
Customer customer = customerService.getCustomer(customerId);
ResponseEntity<Customer> response = new ResponseEntity<Customer>(customer, HttpStatus.OK);
return response;
}
catch(Exception e)
{
throw new ResponseStatusException(HttpStatus.NOT_FOUND,environment.getProperty(e.getMessage()),e);
}
}
here is my service layer method that I'm calling from getCustomerById method -
#Service(value = "CustomerService")
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao customerDao;
#Override
public Customer getCustomer(Integer customerId) throws Exception {
Customer customer = customerDao.getCustomer(customerId);
if (customer == null) {
throw new Exception("Service.CUSTOMER_UNAVAILABLE");
}
return customer;
}
here is my property file
server.port=3557
Service.CUSTOMER_ALREADY_EXIST=Customer already present.Add customer with different attributes.
Service.CUSTOMER_UNAVAILABLE=Customer Details not found. Give valid customer details.
Postman response -
{
"timestamp": "2021-05-02T10:21:22.455+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/DemoBank/customers/8"
}

That's because you throw an exception instead of returning your custom response. Spring's exception always returns 500.
Change this line:
throw new ResponseStatusException(HttpStatus.NOT_FOUND,environment.getProperty(e.getMessage()),e);
to this:
return new ResponseEntity<>(environment.getProperty(e.getMessage()), HttpStatus.NOT_FOUND);

Related

Spring Boot #Valid doesn't display message from #NotBlank

Why message from #NotBlank is not displayed?
Controller API:
#PostMapping("/create-folder")
public SuccessResponse createFolder(Principal principal, #Valid #RequestBody CreateFolderRequest request) {
return historyService.createFolder(principal.getName(), request.getFolderName());
}
Request Body:
#Data
public class CreateFolderRequest {
#NotBlank(message = "Folder name is mandatory.")
private String folderName;
}
JSON Response:
{
"timestamp": "2020-11-18T11:24:19.769+00:00",
"status": 400,
"error": "Bad Request",
"message": "Validation failed for object='createFolderRequest'. Error count: 1",
"path": "/api/history/create-folder"
}
Packages:
Valid:
import javax.validation.Valid;
NotBlank:
import javax.validation.constraints.NotBlank;
There is no global exception handlers in the project.
#Valid throw an exception of MethodArgumentNotValidException you massege in #NotBlank is get throw inside exception detail which isn't return to the customer. you need to extract the messages so try adding this method to the controller.
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return errors;
}
above code read all errors inside the exception then get thier detail (filedName - errorMessage) and put them in list and then return the list to the clinet with 400 bad request status

Unable to do delete operation through spring rest endpoints

I am trying to create a crud application with spring as backend.I have created maaping for fetching,creating and deleting users.However the delet request is not working.The other two mapping work fine.
Here is my repository:
#Repository
public interface UsersRepository extends JpaRepository<Users,Long> {
#Transactional
void deleteByuserName(String username);
}
Here is my controller:
#RestController
public class UsersController {
#Autowired
UsersRepository usersRepository;
#PostMapping(value = "/users/create")
public Users postCustomer(#RequestBody Users user) {
Users _user = usersRepository.save(new Users(user.getUserName(),user.getPassword(),user.getUserRole()));
return _user;
}
#GetMapping("/users")
public List<Users> getAllReports()
{
return usersRepository.findAll();
}
#DeleteMapping(value = "/users/delete/{userName}")
public #ResponseBody void deleteCustomer(#PathVariable("userName") String userName) {
System.out.println("Delete User with name = " + userName + "...");
usersRepository.deleteByuserName(userName);
}
}
The error I get in postman is:
{
"timestamp": "2019-04-12T09:18:51.401+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/users/delete"
}
I might be wrong on this but I would expect the error in postman to be "path": "/users/delete/user"? Are you sure you're passing the username for the path variable?
Does the request ever enter the controller and print your message:
System.out.println("Delete User with name = " + userName + "...");
?

Best practice to send response in spring boot

I'm coding REST Api-s in spring boot. I want to make sure that my code is readable to front-end developers using swagger API development tool (Swagger). For example
#GetMapping("/getOne")
public ResponseEntity<?> getOne(#RequestParam String id) {
try {
return new ResponseEntity<Branch>(branchService.getOne(id), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<FindError>(new FindError(e.getMessage()), HttpStatus.BAD_REQUEST);
}
}
If the request is successful, response is a Branch object, if fails, the response is a FindError object which has only one attribute (message). So both can be carried out depends on the response. But the swagger UI doesn't show how the response should be shown, because I use "?" as generic type. Is this a best practice to catch an error? (This coding documentation swagger is not useful to front-end developers since it doesn't show the response object). Or any best practice for the above problem?
There are a lot of method which return different object like Branch. Thanks in advance
First of all you should follow the best practices of a RESTful API . Don't use verbs, instead use nouns as URL.So instead of #GetMapping("/getOne") , you can write
it as #GetMapping("/branch/{id}") .
You can refer this blog https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
#2ndly , Don't return a generic type as ? , instead you can user the specific type , here as Branch and do central exception handling .
The following code snippet can help you :
#GetMapping("/branch/{id}")
public ResponseEntity<Branch> getBranch(#Pathvariable String id) {
{
Branch branch = branchService.getOne(id);
if(branch == null) {
throw new RecordNotFoundException("Invalid Branch id : " + id);
}
return new ResponseEntity<Branch>(branch, HttpStatus.OK);
}
RecordNotFoundException.java
#ResponseStatus(HttpStatus.NOT_FOUND)
public class RecordNotFoundException extends RuntimeException
{
public RecordNotFoundException(String exception) {
super(exception);
}
}
CustomExceptionHandler.java
#ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler
{
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse error = new ErrorResponse("Server Error", details);
return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(RecordNotFoundException.class)
public final ResponseEntity<Object> handleRecordNotFoundException(RecordNotFoundException ex, WebRequest request) {
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse error = new ErrorResponse("Record Not Found", details);
return new ResponseEntity(error, HttpStatus.NOT_FOUND);
}
}
ErrorResponse.java
public class ErrorResponse
{
public ErrorResponse(String message, List<String> details) {
super();
this.message = message;
this.details = details;
}
private String message;
private List<String> details;
//Getter and setters
}
The above class handles multiple exceptions including RecordNotFoundException and you can also customize for payload validations too.
Test Cases :
1) HTTP GET /branch/1 [VALID]
HTTP Status : 200
{
"id": 1,
"name": "Branch 1",
...
}
2) HTTP GET /branch/23 [INVALID]
HTTP Status : 404
{
"message": "Record Not Found",
"details": [
"Invalid Branch id : 23"
]
}
I would recommend to do it like this .
#GetMapping("/getOne")
public Response getOne(#RequestParam String id) {
ResponseEntity<Branch> resbranch;
ResponseEntity<FindError> reserror;
try {
resbranch=new ResponseEntity<Branch>(branchService.getOne(id), HttpStatus.OK);
return Response.status(200).entity(resbranch).build();
} catch (Exception e) {
reserror=new ResponseEntity<FindError>(new FindError(e.getMessage()), HttpStatus.BAD_REQUEST);
return Response.status(400).entity(reserror).build();
}
}
200 is for OK and 400 is for bad request. Here there wont be anymore ambiguous types..

Response error format with manual validation in Spring Data Rest

When using Spring Data REST and JSR 303 Bean Validation I get a response like the following when there's a constraint violation:
{
"errors": [
{
"entity": "Empresa",
"property": "observacao",
"invalidValue": "",
"message": "O tamanho do campo deve ser entre 1 e 255"
}
]
}
But I'm trying to validate an object manually, and I would like to return the validation errors in the same format used by Spring Data Rest.
#DeleteMapping("/departamento/{id}")
public #ResponseBody
ResponseEntity<?> filtro(#PathVariable Long id){
Optional<Departamento> departamentoOpt = this.departamentoRepository.findById(id);
if (!departamentoOpt.isPresent()) {
return ResponseEntity.notFound().build();
}
Departamento departamento = departamentoOpt.get();
BindingResult errors = new BeanPropertyBindingResult(
departamento, "departamento");
this.validator.validate(departamento, errors, PreDeleteValidation.class);
if (errors.hasErrors()) {
// How to return a response in the same format used by SDR here?
}
return ResponseEntity.ok().build();
}
How can this be accomplished?
You can throw and Exception on validation failure and register a Spring MVC Controller Advice to catch this and transform it to something that meets your needs.
if (errors.hasErrors()) {
throw new org.springframework.web.bind.MethodArgumentNotValidException(
departamento, bindingResult)
}
The advice could look something like the below:
#ControllerAdvice
public class ErrorHandlingAdvice
{
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public ValidationError processValidationError(MethodArgumentNotValidException ex)
{
ValidationError error = new ValidationError();
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
for (FieldError fieldError : fieldErrors)
{
error.addError(fieldError.getField(), fieldError.getDefaultMessage());
}
return error;
}
}
ValidationError is just a simple bean:
public class ValidationError
{
private final Map<String, List<String>> errors;
public ValidationError()
{
errors = new TreeMap<>();
}
public void addError(String field, String error)
{
if (!errors.containsKey(field))
{
errors.put(field, new ArrayList<String>());
}
errors.get(field).add(error);
}
public Map<String, List<String>> getErrors()
{
return errors;
}
}

Return error from spring controller via ajax call

I am trying to develop a spring boot application involving sports, I can not see how to return my error after an ajax call in the error section instead of success, I wonder how I can recuperate all the returns coming from the controller of the Class error in the error section and not in the success section
N.B : Everything work fine in this code, only errors are returned in success part.
Class Error:
public class Error extends Exception{
public String code;
public String message;
}
Class Sport:
public class Sport {
public String id;
public String name;
}
Ajax Call
$.ajax({
type : "GET",
url : "/sports-actions",
data: {"id" : sportId},
contentType: "application/json",
dataType : 'json',
success: function (result) {
console.log(result);
},
error: function (e) {
console.log(e);
}
})
Spring Controller
#RestController
#RequestMapping("/sports-actions")
public class SportController {
#RequestMapping(method = RequestMethod.GET)
public Object deleteSport(#RequestParam("id") String id) {
return new Error(404, "id is not valid");
}
}
Edit
I extended my Error class from Exception, but I have error doing this
throw new Error(400 ,"id is not valid") // I get incompatibale type...
You can do following for testing purpose:
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> deleteSport(#RequestParam("id") String id) {
if({if id exists}) {
return new ResponseEntity<Object>({your response object}, HttpStatus.OK);
} else {
//If the id doesn't exist.
return new ResponseEntity<Error>(new Error(),HttpStatus.BAD_REQUEST);
}
}
Best Practice
You should use #ControllerAdvice to handle exceptions using #ExceptionHandler on method level.
#ControllerAdvice
public class RestControllerAdvice {
#ExeptionHandler(NotFoundException.class)
public ResponseEntity<Error> handleNotFound(NotFoundException nfe) {
//LOG error
Error error = new Error();
error.setCode(HttpStatus.NOT_FOUND);
error.setMessage("ID not found OR Your custom message or e.getMessage()");
return new ResponseEntity<Error>(error, HttpStatus.NOT_FOUND);
}
}
Your controller method
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> deleteSport(#RequestParam("id") String id) {
if({if id exists}) {
return new ResponseEntity<Object>({your response object}, HttpStatus.OK);
} else {
throw new NotFoundException("Id not found");
}
}
Above ControllerAdivce method will get invoked, if your NotFoundException is thrown during request processing. You can always customize the error.
Your current implementation of SportController will return HTTP status 200 which will never go into error: function (e) {. You need to throw an exception from the controller in order to get into error block.
#RestController
#RequestMapping("/sports-actions")
public class SportController {
#RequestMapping(method = RequestMethod.GET)
public Object deleteSport(#RequestParam("id") String id) throws Error {
throw new Error("Test exception block");
}
}

Resources