I am trying to throw a custom exception from Web client onstatus method after checking the Httpstatus.When i tried capturing the thrown exception it was captured as a normal Exception but not the custom exception.
public String getResponse(String request){
try{
randomService.getResponse(request);
}catch(AuthException e){
throw new AuthException(e.getMessage());
}catch(Exception e){
throw new InternalServerError(e.getMessage());
}
}
public String returnResponse(String request){
return webclient.post()
.uri("")
.header("","")
.body(BodyInserters.formatValue(requestMessage))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientRes -> {
if(401){
return Mono.error(new AuthException("traceid)));
}
}).bodyToMono(String.class).block();
}
Not sure what I am doing incorrectly.
I'm facing a weird issue with Wiremock. The code below returns a null response body. Any insight will be very much appreciated.
Stub in my test:
WireMock.stubFor(post(urlPathEqualTo("http://localhost:8080/mapper"))
.willReturn(WireMock.aResponse()
.withStatus(HttpStatus.OK.value())
.withBody(asJson("ct/slotting-response/create_sample_response1.json"))
.withHeader("Content-Type","application/json;charset=UTF-8")));
Actual API call using spring boot resttemplate:
public ResponseEntity<SampleResponse> getsampleValue(final SampleRequest request, RequestHeader requestHeader) throws SlottingException {
try {
log.info("Sending request[payload={}]", request);
final HttpHeaders headers = getRequestHeader(requestHeader);
HttpEntity<?> entity = new HttpEntity<>(request, headers);
final ResponseEntity<SampleResponse> response =
restTemplate.postForEntity("http://localhost:8080/mapper",
entity, SampleResponse.class);
log.info("Sample response {}", response); // response.getBody() gives null
if (HttpStatus.OK.equals(response.getStatusCode())) {
log.info("Sample allocated successfully.");
}
else {
throw new SampleException("failed");
}
return response;
} catch (Exception e) {
throw new SampleException("Failed", e);
}
}
Can someone please point out any obvious mistakes you see in the Wiremock stub?
I have read about controller based exceptions using #ExceptionHandler.
I have read about global exception handling using #ControllerAdvice.
I have also read about extending HandlerExceptionResolver for more in-depth exception handling.
However, what I would ideally like to do is be able to throw a global exception with parameters that dictate a JSON response returned to the client, at any layer in my application.
For instance:
throw new CustomGlobalException(HttpStatus.UNAUTHORISED, "This JWT Token is not Authorised.")
throw new CustomGlobalException(HttpStatus.FORBIDDEN, "This JWT Token is not valid.")
This would then return a JSON response based on the model I've created, along with the status, such as :
{
"success" : "false",
"message" : "This JWT Token is not Authorised."
}
And for this to be returned as a REST response from my controller.
Is something like this possible? Or Do I have to go through the process of making custom error exceptions for everything as described in the documentation.
To clarify, I require the exception to interrupt whatever the ongoing process is, perhaps fetching data from the database, and immediately return the given exception to the client. I have a web mvc setup.
Further details:
#ControllerAdvice
#RequestMapping(produces = "application/json")
public class GlobalExceptionHandler {
#ExceptionHandler(CustomException.class)
public ResponseEntity<Object> handleCustomException(CustomException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getCode());
}
}
Exception thrown here:
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
logger.debug("Filtering request for JWT header verification");
try {
String jwt = getJwtFromRequest(request);
logger.debug("JWT Value: {}", jwt);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken
(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
logger.error("No Valid JWT Token Provided");
throw new CustomException(HttpStatus.UNAUTHORIZED, "No Valid JWT Token Provided");
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
This doesn't exactly do what you want to achieve, but the simplest way of doing almost what you want (and is cleaner, IMO), is to simply define an exception like the following:
#ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException {
public UnauthorisedException(String message) {
super(message);
}
}
Now every time such an exception is thrown (not returned) from a controller method (directly or indirectly), you'll get a response such as
{
"timestamp": "2018-06-24T09:38:51.453+0000",
"status": 401,
"error": "Unauthorized",
"message": "This JWT Token is not Authorised.",
"path": "/api/blabla"
}
And of course the actual status code of the HTTP response will also be 401.
You can also throw a ResponseStatusException, which is more generic and allows you to use the same exception type and pass the status as argument. But I find it less clean.
Following my post on how to handle exception here, you can write your own handler something like this,
class CustomGlobalException {
String message;
HttpStatus status;
}
#ExceptionHandler(CustomGlobalException.class)
public ResponseEntity<Object> handleCustomException(CustomGlobalException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("success", "false");
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getStatus());
}
Code mentioned above will handle CustomGlobalException occurred any layer of code.
Since Spring 5 and Above, a ResponseStatusException (spring framework provided) would be better.
Please refer to spring-response-status-exception
I am trying to create a web application using spring 5 . It's a micro-service which hit few other micro-services. Response from one service is dependent the other.I am using global exception handing in my application.
Here is my code:
#Override
public Mono<Response> checkAvailablity(Request request) {
Mono<Response> authResponse = userService.authenticateToken(request);
return authResponse.doOnSuccess(t -> {
// if success is returned.
// Want to return this innerResponse
Mono<Response> innerResponse =
httpService.sendRequest(Constant.SER_BOOKING_SERVICE_CHECK_AVAILABILTY,
request.toString(), Response.class);
}).doOnError(t -> {
logger.info("Subscribing mono in Booking service - On Error");
Mono.error(new CustomException(Constant.EX_MODULE_CONNECTION_TIMED_OUT));
});
In case of error I want to throw CustomException and catch it in global exception handler:
#ControllerAdvice
public class ExceptionInterceptor {
public static Logger logger = Logger.getLogger(ExceptionInterceptor.class);
#ExceptionHandler(value = CustomException.class)
#ResponseBody
public Response authenticationFailure(ServerHttpRequest httpRequest, ServerHttpResponse response,
CustomException ex) {
logger.info("CustomException Occured with code => " + ex.getMessage());
return buildErrorResponse(ex.getMessage());
}
Based on the above code I have two problems:
The exception which is thrown in Mono.error() is not captured in global exception handler.
In case of success, response from the inner service should be returned.
Used two methods in mono: flatmap() and onErrorMap()
and updated my checkAvailablity() code:
public Mono<Response> checkAvailablity(Request request) {
Mono<Response> authResponse = userService.authenticateToken(request);
return authResponse.flatmap(t -> {
// Added transform() for success case
Mono<Response> response = httpService.sendRequest(Constant.SER_BOOKING_SERVICE_CHECK_AVAILABILTY,
request.toString(), Response.class);
logger.info("Response from SER_BOOKING_SERVICE_CHECK_AVAILABILTY");
return response;
}).onErrorMap(t -> {
// Added onErrorMap() for failure case & now exception is caught in global exception handler.
throw new CustomException(Constant.EX_MODULE_CONNECTION_TIMED_OUT);
});
}
So I am trying to log all uncaught exceptions returned by the controllers of a spring project in a generic fashion.
I was able to do this with the following exception handler:
#ControllerAdvice
public class ControllerConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String DEFAULT_ERROR_VIEW = "error";
#ExceptionHandler(HttpMessageNotReadableException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleBadRequest(HttpMessageNotReadableException e) {
logger.warn("Returning HTTP 400 Bad Request", e);
throw e;
}
#ExceptionHandler(AccessDeniedException.class)
public void defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
logger.error("Error in request:" + request.getRequestURL(), e);
throw e;
}
This also returns the error responses of the request, so I don't have to differentiate between all the different error response codes.
However, for every invocation of the method a second error log is created because of the exception thrown in the method:
Code is from org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
try {
if (logger.isDebugEnabled()) {
logger.debug("Invoking #ExceptionHandler method: " + exceptionHandlerMethod);
}
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);
}
catch (Exception invocationEx) {
if (logger.isErrorEnabled()) {
logger.error("Failed to invoke #ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
}
return null;
}
So is there a smarter way to return the original exception of the method?
It depends on what do you mean by "a smarter way to return the original exception". What exactly would you like to return to the client? If this is just the message of the exception you can simply return it from the exception handler and annotate the method with #ResponseBody. Spring will do the rest for you.
#ExceptionHandler(HttpMessageNotReadableException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public String handleBadRequest(HttpMessageNotReadableException e) {
logger.warn("Returning HTTP 400 Bad Request", e);
throw e.getMessage();
}
You can also return some custom object which wraps the exception information and any other data that you desire.