Normally when we have an interface and there are more than one implementations of the methods declared in the interface we might find it difficult to handle the signature changes for the exceptions thrown in the implementations.
Say we have an interface and 2 implementations.
public interface A {
void methodSignature(String x); // This has to be changed owing to the various Exception thrown from the implementations
}
public class B implements A {
@Override
void methodSignature(String x) throws IOException {
// implementation for B
}
}
public class C implements A {
@Override
void methodSignature(String x) throws ApiException {
// implementation of C
}
}
We can use a common throws Exception in place of IOException and ApiException but if there are more types of exceptions to be handled it might not be clear.
Hence we use @Sneakythrows and send the exceptions to GlobalException handlers annotated with @ControllerAdvice that would control the flow.
public interface A {
void methodSignature(String x);
}
public class B implements A {
@Override
@SneakyThrows
void methodSignature(String x) {
// implementation for B
}
}
public class C implements A {
@Override
@SneakyThrows
void methodSignature(String x) {
// implementation of C
}
}
This in particular helps when we have a contract with the users of the interfaces finalised.
A sample of global exception handler looks like below
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(
value = {HttpMessageNotReadableException.class, DataAccessException.class, Exception.class, RuntimeException.class})
public ResponseEntity defaultWebExceptionHandler(Exception ex, HttpServletRequest servletRequest, HttpServletResponse httpResponse) {
LOGGER.error("A controller threw an exception", ex);
ResponseEntity returnValue = null;
ErrorInfo errorInfo = new ErrorInfo();
try {
throw ex;
} catch (ResourceNotFoundException resourceNotFound) {
errorInfo.setUserMessage(resourceNotFound.getMessage());
errorInfo.setTechnicalDetails(resourceNotFound.getMessage());
errorInfo.setMessageCode(HttpStatus.NOT_FOUND.toString());
returnValue = new ResponseEntity(errorInfo, HttpStatus.NOT_FOUND);
} catch (HttpMessageNotReadableException hme) {
// ...
} catch (DataAccessException dae) {
// ...
} catch (Exception exception) {
// ...
}
configureHttpResponse(httpResponse, null, servletRequest.getRequestURI());
return returnValue;
}
}