Why error is not getting caught, even when explicitly thrown? - java

I want to catch an "Error" in SpringMVC3 using annotated "#ExceptionHandler". I can catch throwable and any exception, but when I tried with "Error" it is not catching the exception. Any idea why? The code below demonstrates the problem.
#Controller
#RequestMapping("/test")
public class TestExceptionController {
static final Logger logger = Logger.getLogger(TestExceptionController.class);
#RequestMapping(method = RequestMethod.GET)
public String processData(int intValue) throws InvalidDataException {
if (intValue < 6) {
try {
throw new Exception();
} catch (Exception e) {
throw new InvalidDataException();
}
}
return "test";
}
#ExceptionHandler(InvalidDataException.class)
public ModelMap handleException(InvalidDataException ex) {
logger.debug("exception catched :" + ex);
return new ModelMap();
}
}
The above code catches, but below code is not catching. Why is it not catching the error?
#Controller
#RequestMapping("/test")
public class TestExceptionController {
static final Logger logger = Logger.getLogger(TestExceptionController.class);
#RequestMapping(method = RequestMethod.GET)
public String processData(int intValue) throws Error{
if (intValue < 6) {
try {
throw new Exception();
} catch (Exception e) {
throw new Error();
}
}
return "test";
}
#ExceptionHandler(Error.class)
public ModelMap handleException(Error ex) {
logger.debug("exception catched :" + ex);
return new ModelMap();
}
}

Actually I looked into the source of spring DispatcherServlet and in line 809 it explains why Error cannot be handled
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
The code is the part where spring processess the ExceptionResolvers may it be annotation or bean based. You can see that Spring only cathces Exception not Throwable. Error is not a subclass of Exception but throwable so you wont be able to handle it with Spring this way. On a related note the annotation is also called #ExceptionHandler so it kind of implies that it wont work with Errors.

From the Error javadocs:
An Error is a subclass of Throwable that indicates serious problems
that a reasonable application should not try to catch. Most such
errors are abnormal conditions. The ThreadDeath error, though a
"normal" condition, is also a subclass of Error because most
applications should not try to catch it.
Catching an Error (or any other Throwable that is not a subclass of Exception) is a bad idea. Spring is doing the right thing by not supporting it.

I also crashed into this, from the code pasted by #peter-szanto seems there is no possibility to handle java.lang.Error with a Spring-registered handler. My use case would be to handle error with a localized page and also to log the error. My workaround is to use web.xml with error-page/error-code 500 defined and as error-page/location a Spring-handled controller (not a JSP) in order to get localization work. Downside is that when controller code runs there is no authentication for the current user. This catches also things Spring could not possibly handle like a wrong URI not mapped to Spring.

For me the below works with Spring 3.0.5 MVC
#ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{
public NotFoundException() {
super();
}
}
#ExceptionHandler
#RequestMapping(method = RequestMethod.GET, value = "employee/{id}",
headers = "Accept=application/json,application/x-protobuf,application/xml")
public #ResponseBody method(xxxx)
{
..
throw new NotFoundException
...
}

didnt meant to handle Exception instead of Error? Error is very ralely used in Java and has a very few implementing classes.

Related

Java Spring exception handling

I have multiple controllers whose exceptions are handled in the ControllerAdvice.
All controllers use common exceptions types (like HttpClientException, DBException, etc.).
But there is one specific controller which exceptions should be handled differently.
In my current implementation all methods of this specific controller are wrapped with try-catch and throw CustomException in case of any exception. Then, in ControllerAdvice I process this type of exception.
However, I want to handle all exceptions in ControllerAdvice as well as get rid of CustomException and try-catch in controller methods.
Is there any way to find out the source controller name in the exception advice? I could check it and handle the exception differently.
Or maybe some other solution exist?
Inside of your controller advice, you can provide Handler for your custom exception as below.
#ControllerAdvice
public class CustomGlobalExceptionHandler {
#ExceptionHandler(CustomException.class)
public final ResponseEntity<ApiResponseDTO> manageException(CustomException ex) {
log.error("Error in CustomException: {}", ex.getMessage(), ex);
ApiResponseDTO error = ApiResponseDTO.builder()
.message(ex.getMessage())
.result(0)
.build();
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(CustomException1.class)
public final ResponseEntity<ApiResponseDTO> manageException1(CustomException1 ex) {
log.error("Error in CustomException1: {}", ex.getMessage(), ex);
ApiResponseDTO error = ApiResponseDTO.builder()
.message(ex.getMessage())
.result(0)
.build();
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(Exception.class)
public final ResponseEntity<ApiResponseDTO> manageException1(Exception ex) {
log.error("Error in Common Exception Handler: {}", ex.getMessage(), ex);
StackTraceElement[] ste = ex.getStackTrace();
String className=ste[ste.length - 1].getClassName();
System.out.println(className);
if(className.equalsIgnoreCase("com.a")){
System.out.println("Do A related stuff");
}else{
System.out.println("Do B related stuff");
}
ApiResponseDTO error = ApiResponseDTO.builder()
.message(ex.getMessage())
.result(0)
.build();
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
}
As mentioned in last block, you can get class name from where this exception thrown and utilizing that name to branching out your stuff.

How to get a 409 for ObjectOptimisticLockingFailureException with Spring Boot?

I know that Spring Boot will render a Thymeleaf template at error/409.html for an exception that leads to a statuscode of 409 CONFLICT by default. However, it seems that ObjectOptimisticLockingFailureException gives a 500 SERVER ERROR by default.
I am able to handle the exception and "manually" redirect to the error/409.html template using a #ControllerAdvice like this:
#ControllerAdvice
public class GlobalControllerAdvice {
#ResponseStatus(HttpStatus.CONFLICT)
#ExceptionHandler({DataIntegrityViolationException.class, ObjectOptimisticLockingFailureException.class})
public ModelAndView handleConflict(HttpServletRequest request, Exception e) {
ModelAndView result = new ModelAndView("error/409");
result.addObject("url", request.getRequestURL());
return result;
}
}
Since ObjectOptimisticLockingFailureException is not part of my own code, I cannot annotate it with #ResponseStatus(HttpStatus.CONFLICT) to have a 409.
Is it possible to map ObjectOptimisticLockingFailureException to 409 and use the default error template mechanism for error codes in Spring Boot?
We can try with ResponseEntity as below
#ExceptionHandler({DataIntegrityViolationException.class, ObjectOptimisticLockingFailureException.class})
public ResponseEntity<ModelAndView> handleConflict(HttpServletRequest request, Exception e) {
ModelAndView result = new ModelAndView("error/409");
result.addObject("url", request.getRequestURL());
return new ResponseEntity<>(result, HttpStatus.CONFLICT);
}
This might work
#Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r =
new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("ObjectOptimisticLockingFailureException", "error/409");
r.setExceptionMappings(mappings);
return r;
}
Could you catch the exception ObjectOptimisticLockingFailureException and re-throw an exception with 409?
try {
//perform your task here
} catch (ObjectOptimisticLockingFailureException e) {
var ex = new ClientErrorException(409, e);
throw ex;
}

ControllerAdvice conditionally handle exception

I have a controller advice that handles the exceptional behavior in my REST controller and I came across a situation when I have to conditionally process SQLIntegrityConstraintViolationException that have a certain message (the one for duplicate keys), returning a 409, letting the other ones be handled by the default handler (returning a 500 error code).
I am thinking of 2 possible ways to achieve that:
Throwing a new bare-boned Exception on the else branch on my condition, so the handling is done by Spring.
Explicitly calling the general exception handler (like return handleGeneralException(exception) from inside my else branch).
I there a "proper" way to pass on a fraction of exceptions of one kind in my ControllerAdvice to another handler than the "original" one?
EDIT 1:
I would like to do something like this in my ControllerAdvice:
if (exception.getMessage.contains("something")) {
// handle exception
} else {
// pass to other handler
}
Have a custom exception class and then when you throw the SQLIntegrityConstraintViolationException wrap it in your custom exception classs with additional fields whatever you want to be accessible in controller advice. Handle the custom exception in your controller advice class.
#ControllerAdvice
public class CustomExceptionHandler {
#ExceptionHandler(YourCustomException.class)
public final ResponseEntity<ExceptionResponse> handleNotFoundException(YourCustomExceptionex,
WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(),
request.getDescription(false), HttpStatus.NOT_ACCEPTABLE.getReasonPhrase());
return new ResponseEntity<>(exceptionResponse, HttpStatus.CONFLICT);
}
}
While having the try catch block to handle this exception in your code , make sure that you handle DataIntegrityViolationException instead of SQLIntegrityConstraintViolationException if you are using Spring Data JPA. So , if you are using Spring Data Jpa then :
try {
anyRepository.save(new YourModel(..));
} catch (DataIntegrityViolationException e) {
System.out.println("history already exist");in res
throw New YourCustomException("additional msg if you need it ", e);
}
Below code will capture the error message of exception SQLIntegrityConstraintViolationException in ControllerAdbvice without having to handle in code
#ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = DataIntegrityViolationException.class)
public ResponseEntity<ExceptionResponse> dataIntegrityViolationExceptionHandler(Exception ex) {
ExceptionResponse response = new ExceptionResponse();
Throwable throwable = ex.getCause();
while (throwable != null) {
if (throwable instanceof SQLIntegrityConstraintViolationException) {
String errorMessage = throwable.getMessage();
response.setErrors(new ArrayList<>(Arrays.asList(errorMessage)));
}
throwable = throwable.getCause();
}
return new ResponseEntity<Object>(response, HttpStatus.CONFLICT);
}
}

How to handle exception in spring with #ControllerAdvice even though we are handling exception in catch block

Not able to use #ControllerAdvice and #AfterThrowing when method surrounded by try and catch block.
I can explain step by step
Step 1: In my spring application all handlers(methods) are handle exception by try and catch block.
Step 2: So requirement i need to trigger a email when the exception occurs in all handlers methods. But my application having 100's of methods. So try with #ControllerAdvice to handle the exceptions by using #ExceptionHandler annotation. I know that it wont work because we already handling our exception in catch block. So it cant look at #ControllerAdvice.
Step 3: I try with Aop #AfterThrowing advice also. It is not working. So i cant able to remove all catch blocks in entire application code. It is very difficultly to do that.
But my question is that
Is there any way in spring to handle the exception even we are handling it.
We returning back status code like 400 . In Spring they any Advice to identify status code.
Because are retiring ResponseEntity Status back as response.
#RequestMapping(value = "/service/getDetails", method = RequestMethod.POST, produces = { "application/json" })
public ResponseEntity<Map<String, Object>> getDetails(#RequestBody Details details, HttpServletRequest request) {
ResponseEntity<Map<String, Object>> response = null;
try {
/// Some code
} catch (Exception e) {
logger.error("Exception while DetailsController: " + e.getMessage());
response = new ResponseEntity<>(HttpStatus.BAD_REQUEST);
/*
* int status=response.getStatusCodeValue();
* scheduledMailTrigerService.sendErrorLogInfo(request,e,status);
*/
}
return response;
}
#ControllerAdvice
public class AppExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = { Exception.class })
public String handleAnyException(Exception ex, WebRequest request) {
System.out.println("Done");
return "Done";
}
}
You can use an #Around advice to capture the result of the method execution... my suggestion is that you remove the try catch from all your endpoints, just write a try catch wrapping the ProceedingJoinPoint proceed() execution. This way you can return a ResponseEntity 400 when an exception occurs, alongside execututing email sending logic.

Spring Soap Webservice exception handling

I am creating soap web service using spring. I am getting hibernate exception while trying to save the request.
I am trying to catch the hibernate exception in the catch block but control not even coming to the catch block
and soap service returning with the soap fault error message. Below are the list of classes which i am using,
Could any one please let me know how to handle the exception and rethrow the exception.
#WebService(serviceName = "submitService")
public class SubmitService extends AbstractWebServiceImpl {
#Autowired
private Validate validate;
#WebMethod
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public ResponseData submitRequest(RequestData request) {
ResponseData response = validate.submitRequest(request);
return response;
}
}
My Base class
public class AbstractWebServiceImpl extends SpringBeanAutowiringSupport {
#Resource
private WebServiceContext webServiceContext;
protected void handleWSException(Exception e) throws BusinessFault, InfrastructureFault {
if ( e instanceof BusinessException) {
ReturnMessage rm = ((BusinessException)e).getReturnMessage();
throw new BusinessFault(rm, e);
} else if (e instanceof BaseException) {
ReturnMessage rm = ((BaseException)e).getReturnMessage();
throw new InfrastructureFault(rm, e);
} else {
ReturnMessage rm = new ReturnMessage(ReturnCode.GENERIC_WEB_SERVICE_ERROR, e.toString());
throw new InfrastructureFault(rm, e);
}
}
public void setWebServiceContext(WebServiceContext webServiceContext) {
this.webServiceContext = webServiceContext;
}
public WebServiceContext getWebServiceContext() {
return webServiceContext;
}
}
My Business layer implementation class
#Component
public class ValidateImpl implements Validate {
#Autowired
private SomeHibernateDao dao;
#Override
#Transactional
public ResponseData submitRequest(RequestData request) {
ResponseData response = new ResponseData();
try {
dao.save(request);
} catch (Exception e) {
// Control never execute this block of code if dao layer throwing any exception.
// I want to catch the exception here modify the response and return to the client
e.printStackTrace();
response.setErrorDetails("More meaningful error message");
}
return response;
}
This code returning default soap error message back to client.
I want to catch the exception and modify the exception before returning to client. Please let me know what change i have to make so that i can handle the soap error message before i return the response back to client.
I am able to catch the exception in SubmitService itself but not sure why not able to catch the exception in ValidateImpl. however my issue is resolved now.

Categories