Issue
When the user creates a record with a name that's already exists in the DB , I'm returning a specific Exception.
@PostMapping("/campaigns")
public ResponseEntity<CampaignDTO> saveCampaign(@RequestBody CampaignDTO campaignDTO) throws ApiErrorResponse, Exception {
if (this.campaignService.getCampaignByName(campaignDTO.getName()) != null) {
throw new IllegalArgumentException("The value already exists!");
}
if (campaignDTO.getProducts() == null) {
ApiErrorResponse errorReponseDto = new ApiErrorResponse("No Products attached");
throw errorReponseDto;
}
campaignDTO = campaignService.saveCampaign(campaignDTO);
ResponseEntity<CampaignDTO> responseEntity = new ResponseEntity<>(campaignDTO , HttpStatus.CREATED);
return responseEntity; // return 201
}
And the Exception that I want to return to the Client is:
public class ApiErrorResponse extends Throwable {
private final String error;
//Any addtional info you might later want to add to it
public ApiErrorResponse(String error){
this.error = error;
}
public String getError(){
return this.error;
}
}
However , when I throw
IllegalArgumentException("The value already exists!")
It is caught by
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
How can we prevent this , and return "ApiErrorResponse" when the user inserts the same name ?
I want to return my Exception , not anything else.
Solution
Here you have few decision. I will mark 2 of them. 1st is to return directly BadRequest for example with specific DTO - It is not best example with the Throwable, but you can create new ErrorResponseDTO:
@PostMapping("/campaigns")
public ResponseEntity<?> saveCampaign(@RequestBody CampaignDTO campaignDTO) throws ApiErrorResponse, Exception {
if (this.campaignService.getCampaignByName(campaignDTO.getName()) != null) {
ApiErrorResponse errorReponseDto = new ApiErrorResponse("The value already exists!");
return ResponseEntity.badRequest().body(errorReponseDto) // return 400
}
if (campaignDTO.getProducts() == null) {
ApiErrorResponse errorReponseDto = new ApiErrorResponse("No Products attached");
return new ResponseEntity<>(errorReponseDto , HttpStatus.BAD_REQUEST); // return 400
}
campaignDTO = campaignService.saveCampaign(campaignDTO);
ResponseEntity<CampaignDTO> responseEntity = new ResponseEntity<>(campaignDTO , HttpStatus.CREATED);
return responseEntity; // return 201
}
Other way is to use @ControllerAdvice
which will handle exception and will return what you want. This advice will be triggered after you throw the exception:
@ControllerAdvice
public class MyAdvice {
@ExceptionHandler(value = ApiErrorResponse.class)
public ResponseEntity<MyErrorResponse> handleException(ApiErrorResponse exception) {
return return ResponseEntity.badRequest().body(MyErrorResponse)
}
}
Answered By - Емилиян Йорданов
Answer Checked By - Cary Denson (JavaFixing Admin)