I am getting NotFoundException while trying to implement custom exception handling in spring-boot rest application.
The code was working fine when I was using MVC (using #ControllerAdvice) annotations but not sure when I am sending a data which is violating the constraint mentioned in entity(pojo class) it is throwing only NotFoundException (for all validation failure) but not the MethodViolationException or ConstraintViolationException
I am not able to send the message for that particular violation.
Not sure where I am making this mistake. Please help
Code:
#POST
#Path("/customers/add")
public Response addCustomer(#Valid customer cust)
{
// Rest of the code
}
POJO:
#Entity
#Table(name="cust")
public class Customer
{
#NotNull
#Size(min=1,max=50,message ="invalid name")
String name;
}
Exception Handler:
#Provider
public class CustomHandler implements ExceptionMapper<Exception>
{
public Response toResponse(Exception ex)
{
if(ex instanceOf ConstraintViolationException)
{
Do something
}
}
**UPDATE 1
If I enable the send_error_in_response i am getting the message for this but not sure why my custom exception handler is not able to catch this exception and only throwing NotFoundException
Try Handling Exception Using:
#ControllerAdvice
#RestController
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(StudentNotFoundException)
public final ResponseEntity<ErrorDetails> handleUserNotFoundException(StudentNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
For more information you might want to refer http://www.springboottutorial.com/spring-boot-validation-for-rest-services
Related
Hi I am new to spring boot.when I try submit the request from the postman it is returning org.springframework.transaction.TransactionSystemException with HttpStatus code : 500 if invalid it throwing the javax.validation.ConstraintViolationException in the server.
Can any one share the best solution to handle these exceptions?
I tried in controller with the below code:
#ExceptionHandler(ConstraintViolationException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
return new ResponseEntity<>("not valid due to validation error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
}
But I want the response to be send in Json format with customized error message How can I achieve it ?
And also wanted to avoid the exception handling code in the controller.Is there any better way?
Each of such exceptions must be handled separately like below
#RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler ({ConstraintViolationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleConstraintViolationException(
ConstraintViolationException e) {
return new ResponseEntity<>(new JsonErrorResponse(e.getMessage()), HttpStatus.BAD_REQUEST);
}
}
If you want to create your own response object then u can use the below way in the RestExceptionHandler class.
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException e, HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<>(new CustomErrorResponse(e.getMessage()), HttpStatus.BAD_REQUEST);
}
private class CustomErrorResponse {
String message;
public CustomErrorResponse() {
}
public CustomErrorResponse(String message) {
super();
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
You can use #ControllerAdvice. It's a special component to handle error across the hole application. Here I show you a example:
#ControllerAdvice
public class CustomErrorHandler{
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<String> handleContraintViolationException() {
// Your custom response
}
}
The pro is that you have a different class that handle the exceptions in all the application.
500 is a server problem. It means your server encounter a problem while executing the code. Specifically it's ConstraintViolationException which means you have a constraint when inserting your data in the database.
Example :
Imagine we have an entity that has a unique field
#Entity
user {
UUID id;
#column
String name;
}
and when creating the entity you have made a uniquness contrainte in database :
ALTER TABLE USER
ADD CONSTRAINT UC_name UNIQUE (name);
Here if you try to insert two user with the same name you would receive a ConstraintViolationException
I'm having a peculiar situation with my #ControllerAdvice annotated ExceptionHandler in Spring Boot 1.5.3. It catches any exceptions default Exceptions, but if I throw a custom exception it does not fire.
The ExceptionHandler:
#ControllerAdvice
public class ResponseEntityExceptionHandler {
#ExceptionHandler({ HttpMessageNotReadableException.class })
protected ResponseEntity<ErrorModel> handleInvalidJson(RuntimeException e, WebRequest request) {
return new ResponseEntity<ErrorModel>(new ErrorModel().message("Could not parse JSON."), HttpStatus.BAD_REQUEST);
}
#ExceptionHandler({ NumberFormatException.class })
protected ResponseEntity<ErrorModel> handleInvalidRequest(RuntimeException e, WebRequest request) {
return new ResponseEntity<ErrorModel>(new ErrorModel().message("Invalid request parameter."), HttpStatus.BAD_REQUEST);
}
#ExceptionHandler({ CannotCreateTransactionException.class })
protected ResponseEntity<ErrorModel> handleTransactionCreationException(RuntimeException e, WebRequest request) {
return new ResponseEntity<ErrorModel>(new ErrorModel().message("Error connecting to the database, please make sure it is still available."), HttpStatus.BAD_REQUEST);
}
#ExceptionHandler({ NotFoundException.class })
protected ResponseEntity<ErrorModel> handleApiException(RuntimeException e, WebRequest request) {
return new ResponseEntity<ErrorModel>(new ErrorModel().message(e.getMessage()), HttpStatus.NOT_FOUND);
}
}
The top 3 Exceptions all get caught and handled as they are supposed to, but the bottom Exception gets handled by the default Spring-Boot ExceptionHandler. It is a custom Exception that I throw inside a Controller:
public ResponseEntity<?> deleteActor(#ApiParam(value = "Used to identify a single actor.", required = true) #PathVariable("actor_id") Integer actorId, #RequestHeader("Accept") String accept) throws Exception {
Actor actor = actorRepository.findOne(actorId);
if (actor == null) {
throw new NotFoundException(404, "Not found");
}
actorRepository.delete(actorId);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
I've tried throwing one of the top Exceptions like this:
public ResponseEntity<?> readActor(#ApiParam(value = "Used to identify a single actor.", required = true) #PathVariable("actor_id") Integer actorId, #RequestHeader("Accept") String accept) throws Exception {
Actor actor = actorRepository.findOne(actorId);
if (actor == null) {
throw new NumberFormatException("");
}
return new ResponseEntity<Actor>(actor, HttpStatus.OK);
}
and these get handled just fine...
The tomcat logs also show this:
2017-06-05 11:30:20.080 INFO 9076 --- [ main] .m.m.a.ExceptionHandlerExceptionResolver : Detected #ExceptionHandler methods in responseEntityExceptionHandler
The Exception:
public class NotFoundException extends ApiException {
private int code;
public NotFoundException (int code, String msg) {
super(code, msg);
this.code = code;
}
}
The exception inherits from this baseclass:
public class ApiException extends Exception{
private int code;
public ApiException (int code, String msg) {
super(msg);
this.code = code;
}
}
Any ideas about why the custom Exception avoids detection by the ExceptionHandler?
I would be happy to provide additional information should that be necessary.
For this particular case the answer is to use Exception instead of RuntimeException, since NotFoundException does only inherit from Exception.
Further notable things:
To catch all exceptions one can use an #ExceptionHandler(Exception.class)
If using common names for exceptions, always check if you have imported the right one.
For me the CustomException was not getting caught by #ControllerAdvice method. I searched for hours and finally the issue got resolved on Updating the project.
Right click on your project -> Maven -> Update project.
I'm trying to handle exceptions in a spring boot application that has SOAP endpoints and Rest controllers.
Catching exceptions that occur in the rest controller is quite straightforward, I just set a class with #controlleradvice that has #exceptionhandler methods and all exceptions get caught. However, this controlleradvice doesn't seem to catch exceptions that occur in the SOAP endpoints. Is there a way to catch the exceptions that are thrown in the endpoints on a #controlleradvice class? If not, is there some other way to centralize exception handling throughout the entire application, independently from where the exceptions are thrown?
Thank you so much in advance.
We can create customized exception:
#ResponseStatus(HttpStatus.NOT_FOUND) public class StudentNotFoundException extends
RuntimeException {}
Exception handler in Spring:
#ControllerAdvice
#RestController
public class CustomizedResponseEntityExceptionHandler extends
ResponseEntityExceptionHandler {
#ExceptionHandler(StudentNotFoundException.class)
public final ResponseEntity<ErrorDetails>
handleUserNotFoundException(StudentNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
Let's say I have the following runtime exception:
#ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public class ExpectationsFailedException extends RuntimeException {
public ExpectationsFailedException(String message) {
super(message);
}
}
My question is if it is ok to throw the previous HTTP exception in my service layer or should I throw it from my controller:
#Service
public class UserService {
#Autowired
...
public void addUser(final String email, final String username, final String password){
if(parameters_are_not_valid){
throw new ExpectationsFailedException("Invalid input");
}
}
}
The controller exception throwing solution would be the following:
#Service
public class UserService {
#Autowired
...
public void addUser(final String email, final String username, final String password) throws InvalidInputParameters {
if(parameters_are_not_valid){
throw new InvalidInputParameters("Invalid input");
}
}
}
and in my controller
#RestController
public class XController{
#Autowired
private UserService userService;
#RequestMapping(value = "/addUser", method = RequestMethod.POST)
public void addUser(#Valid #RequestBody SignUpForm form, BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ExpectationsFailedException("Input parameters conditions were not fulfilled");
}
try {
userService.addUser(...);
}
catch(InvalidInputParameters ex){
throw new ExpectationsFailedException("Invalid service input parameters");
}
}
}
Which of those solutions is preferred? Why? I have a feeling that I should not throw HTTP exceptions in my services because I may use that services in other contexts which may not be related to HTTP.
I would go with the second one.
What do you think?
I agree with your last statement. Your service layer should be independent of HTTP or frontent frameworks (#ResponseStatus is Spring MVC annotation and therefore it's not the best practice to use it in your service layer).
However you don't have to throw one exception in service layer, catch it in controller and rethrow another exception annotated with #ResponseStatus. Just add exception handler for the service exception and return appropriate response status from it. You have plenty of options, for instance #ExceptionHandler:
#ResponseStatus(HttpStatus.EXPECTATION_FAILED)
#ExceptionHandler(InvalidInputParameters.class)
public void handle() {
// Do nothing, just return the status
}
You can put this code to #ControllerAdvice annotated class to enable it for all controllers or just in you controller if it's not needed elsewhere.
I am developing a project using Spring REST web services, where I need to show graceful error messages when an exception/error occurs. I followed this tutorial (http://www.javacodegeeks.com/2013/02/exception-handling-for-rest-with-spring-3-2.html) for exception handling using SpringREST. I get the proper output when there is no exception/error i.e. in form of an XML. The issue arises when an exception occurs. Here is part of the code base where an exception occurs if I do not pass the testId in
localhost:8080/test?testId=
The class outputs a response in form of a XML, so when an exception occurs, instead of showing the error message as figure 1 below, it shows error message as figure 2. If I do "View Page Source", I get the correct exception message (as figure 1). But I need the exception message directly. Could anyone, please suggest a solution?
#RequestMapping(value = "/test",
method = RequestMethod.GET,
produces = "application/xml")
public #ResponseBody String testResource(
#RequestParam(value="testId", required=true) String testId)
throws CustomRestException{
if (testId == null || testId.equals(""))
{
LOG.error( "testResource(): " + TestUtilsException.NULL_TEST_ID_ERROR_MSG );
//The error message is: The test Id is required and cannot be null or empty
throw new CustomRestException(TestUtilsException.NULL_TEST_ID_ERROR_MSG);
}
}
Figure 1
Figure 2
Other helper classes:
#ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
public RestResponseEntityExceptionHandler() {
super();
}
#ExceptionHandler(value = { CustomRestException.class })
#ResponseBody
protected ResponseEntity<Object> handleNotFound(final RuntimeException ex, final WebRequest request) {
final String bodyOfResponse = ex.getMessage();
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
}
public class CustomRestException extends RuntimeException {
public CustomRestException() {
super();
}
public CustomRestException(final String message, final Throwable cause) {
super(message, cause);
}
public CustomRestException(final String message) {
super(message);
}
public CustomRestException(final Throwable cause) {
super(cause);
}
}
The #ControllerAdvice approach should work, although I don't think there's any need for the base class - you can just use #ExceptionHandler with Spring 4. But you are returning a response body that cannot be converted to Xml (it's a plain String), so you are getting an empty response and probably a 405 instead of a 500. If you want an Xml response you have to provide a body that can be converted (or else provide an HttpMessageConverter that can do it).
Consider doing this.
public class BaseController{
#ExceptionHandler(value = { CustomRestException.class })
protected #ResponseBody ResponseEntity<ErrorResponse > handleNotFound(final RuntimeException ex, final WebRequest request) {
System.out.println("is executed in handler");
final String bodyOfResponse = ex.getMessage();
return new ResponseEntity<ErrorResponse >(new ErrorResponse (bodyOfResponse), null, HttpStatus.NOT_FOUND);
}
}
In your controller do this.
#Controller
public class HomeController extends BaseController {//Your code here}
And create this class.
#XmlRootElement
public class ErrorResponse {
public String error;
}
Finally add to your class the following code
if (testId == null || testId.equals(""))
{
throw new CustomRestException("DD");
}
That will create an XML response as follows.
This XML file does not appear to have any style information associated
with it. The document tree is shown below.
<successResponse> <error>DD</error> </successResponse>
This will handle all the exception an is not needed to add #ControllerAdvice, that seems need to add their own MessageConverters that is why the answer is not converted to XML, I read that here.
I added ,produces = "application/xml" and remove it, and is still working as I think you want. Please let me know if this was useful.