I trying to write custom exception mapper for CompletionException and to show image in case of this excption. This is my mapper:
#Provider
public class CustomCompleteExceptionManager implements ExceptionMapper<CompletionException> {
#Override
public Response toResponse(CompletionException e) {
return Response
.status(Response.Status.BAD_REQUEST)
.entity(Paths.get("error.png").toFile())
.type("image/img")
.build();
}
Method toResponse is called when my code throws CompletionException, but browser doesn't displays error.png. I get an error:
This site can’t be reached
The webpage at http://localhost:8080/cf/point might be temporarily down or it may have moved permanently to a new web address.
When I write just String message to Response it works fine:
#Provider
public class CustomCompleteExceptionManager implements ExceptionMapper<CompletionException> {
#Override
public Response toResponse(CompletionException e) {
return Response
.status(Response.Status.BAD_REQUEST)
.entity(e.getMessage())
.build();
}
What could be the problem?
The media type set in response is wrong.
It should be .type("image/png") not image/img.
This is the code when I tested in my local.
return Response
.status(Response.Status.BAD_REQUEST)
.entity(Paths.get("/home","kishore","Pictures","Meme.png").toFile())
.type("image/png")
.build();
Related
Right now i'm using this example of exception handling:
//get an object of type curse by id
//in the service file, this findCurseById() method throws a
//CursaNotFoundException
#GetMapping("/{id}")
public ResponseEntity<curse> getCursaById (#PathVariable("id") Long id) {
curse c = curseService.findCurseById(id);
return new ResponseEntity<>(c, HttpStatus.OK);
}
//so if not found, this will return the message of the error
#ResponseStatus(HttpStatus.NOT_FOUND)
#ExceptionHandler(CursaNotFoundException.class)
public String noCursaFound(CursaNotFoundException ex) {
return ex.getMessage();
}
and that's my exception
public class CursaNotFoundException extends RuntimeException {
public CursaNotFoundException(String s) {
super(s);
}
}
in future I want to use Angular as front-end, so I don't really know how I should treat the exceptions in the back-end. For this example let's say, should I redirect the page to a template.html page in the noCursaFound() method, or should I return something else? A json or something? I couldn't find anything helpful. Thanks
I would suggest keeping the error handling at the REST API level and not redirecting to another HTML page on the server side. Angular client application consumes the API response and redirects to template.html if needed.
Also, it would be better if the backend returns an ApiError when an exception occurs with a message and, optionally, an error code:
public class ApiError {
private String message;
private String code;
}
and handle the exceptions in a separate class, ExceptionHandler annotated with #ControllerAdvice:
#ControllerAdvice
public class ExceptionHandler {
#ExceptionHandler(value = CursaNotFoundException.class)
public ResponseEntity cursaNotFoundException(CursaNotFoundException cursaNotFoundException) {
ApiError error = new ApiError();
error.setMessase(cursaNotFoundException.getMessage());
error.setCode(cursaNotFoundException.getCode());
return new ResponseEntity(error, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(value = Exception.class)
public ResponseEntity<> genericException(Exception exception) {
ApiError error = new ApiError();
error.setMessase(exception.getMessage());
error.setCode("GENERIC_ERROR");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I have an Microservice and it gets an response from another. And based on the response I get I need to respond accordingly. I have no complete List of Error code I can receive, so the question is - can I generate error codes on the fly for my own response? From what I saw in spring the responses are predefined in code. I need to be flexible.
For example:
I receive a 409 I will respond with 409
I receive a 400 I will respond with 400
I receive a XXX code I will respond with XXX.
Try this code: (Sample code)
#RequestMapping(value = "/validate", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<ErrorBean> validateUser(#QueryParam("jsonInput") final String jsonInput) {
int numberHTTPDesired = 400;
ErrorBean responseBean = new ErrorBean();
responseBean.setError("ERROR");
responseBean.setMessage("Error in validation!");
return new ResponseEntity<ErrorBean>(responseBean, HttpStatus.valueOf(numberHTTPDesired));
}
I have worked on such a use case using the following concept. Try to create a generic exception across micro services. Take 2 params in the exception as error message and another one as error code. Throw the exception from the service being called and catch the same exception in the calling service in the rest template or feign client call.
public class MyException extends Exception {
private String errorCode;
public MyException() {
super();
}
public MyException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
}
--
try {
return myApiService.getUser();//call to myApiService microservice
} catch (MyException e) {
logger.error("Error: {}", e.getMessage());
throw new MyException(e.getMessage(), e.getCode());
}
I am using jersey for REST web services.
I am handling all 404 responses by throwing NotFoundException(Package com.sun.jersey.api) whenever I don't get any object from service layer.
e.g.
#GET
#Path("/{folderID}")
#Produces(MediaType.APPLICATION_JSON)
public Response getFolder(#PathParam("folderID") int folderID) {
.
.
.
Folder folderObj = folderService.getFolder(folderID);
if(folderObj == null){
throw new NotFoundException("Folder with ID '"+folderID+"' not found.");
}
}
I have written ExceptionMapper for this exception.
#Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
public Response toResponse(NotFoundException ex) {
ErrorMesage errorMessage = new ErrorMessage();
errorMessage.setCode(Status.NOT_FOUND.getStatusCode());
errorMessage.setMessage(ex.getMessage());
return Response.status(Status.NOT_FOUND)
.entity(errorMessage)
.type(MediaType.APPLICATION_JSON)
.build();
}
}
So When I give unknown folder ID as path parameter, exception is thrown but code in NotFoundExceptionMapper is not invoked. (I can see exception message in response but as 'plain text', even though in mapper I am returning response in JSON; and debug break point is also not hit).
Also, Above exception mapper is invoked when I enter incorrect resource name in URI, but not for incorrect path param.
I have also added exception mapper like below to respond to all other exceptions.
public class GenericExceptionMapper implements ExceptionMapper<Throwable>{
public Response toResponse(Throwable ex) {
ErrorMessage errorMessage = new ErrorMessage();
errorMessage.setCode(Status.INTERNAL_SERVER_ERROR.getStatusCode());
errorMessage.setMessage(ex.getMessage());
return Response.status(errorMessage.getCode())
.entity(errorMessage)
.type(MediaType.APPLICATION_JSON)
.build();
}
Above code is called whenever any exception (other than mapped exceptions) is thrown and I get proper JSON response.
So what is wrong with NotFoundException here?
I have googled about this and also looked into source of NotFoundException but didn't find anything useful, please guide me on this.
A snippet from the jersey ServerRuntime class. It has a special logic that if the Exception is an instance of WebApplicationException and has a body, it does not go to the exception mappers at all.
private Response mapException(Throwable originalThrowable) throws Throwable {
if (throwable instanceof WebApplicationException) {
WebApplicationException webApplicationException = (WebApplicationException)throwable;
}
this.processingContext.routingContext().setMappedThrowable(throwable);
waeResponse = webApplicationException.getResponse();
if (waeResponse.hasEntity()) {
LOGGER.log(java.util.logging.Level.FINE, LocalizationMessages.EXCEPTION_MAPPING_WAE_ENTITY(waeResponse.getStatus()), throwable);
return waeResponse;
}
long timestamp = this.tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING);
ExceptionMapper mapper = this.runtime.exceptionMappers.findMapping(throwable);
}
I am calling REST webservices from JSP using AJAX . Can you tell me the best way to send custom error message from REST webservice to JSP ?
Consider using HTTP response codes with (possibly) json response bodies to supply any required information so the client application can react accordingly.
Consider using the WebapplicationException. You can give it the Errorcode (also custom ones) and a body for the response. You could use the JSON Format if you have a complex structure to display your errors but i would suggest just using the an errormessage (for example in case of a bad request, what part of the request was bad).
If you are using JAX-RS REST webservice, you can configure Spring #Controller. Your method should produce application/json and return Response object, like in this example:
#GET
#Path("/get/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserById(#PathParam("id") String userId) {
// Here your logic
Foo foo = new Foo();
foo.setMsg("Bad Request");
foo.setData("User " + userId + " not found")
return Response.status(400).entity(foo).build();
}
And from AJAX, you can catch error message
// Get user details
$.getJSON(encodeURI("./rest/user/get/" + userId), function(data) {
// Some logic on success
// Fail
}).fail( function(jqxhr) {
console.log(jqxhr.responseJSON.msg);
});
There are a couple of ways.
1. You can look at the response status you receive from the web service. The statuses starting with 2** are a success response (Eg: 200, 201), the ones starting with 4** or 5** are errors.
But the optimal way to handle and track exceptions is to use ExceptionMapper. You can write your own class that implements ExceptionMapper like below:
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}
You can write your own custom exceptions like below or can throw blanket exception like below. The above approach is the preferred one though.
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}
I have question that interest me.
Assume that I have some rest controller and some rest client writing in javascript. This client send request to a controller and during a processing occur some error. How should behave controller in this situation? Should return null? or string with message?
For example, We have controller like this:
#RequestMapping("/user", method = RequestMethod.POST)
public #ResponseBody String createUser(User user) {
try {
userService.create(user);
} catch(UserCreationException e) {
}
}
This is very simple example but is many different examples of controllers like controller which return some resources or only change state on the server side and I don't know what to do when occur error.
in improving developer(your consumers) experience , it is a good idea to respond with appropriate error messages on the response body in addition to the Http status code.
Here is an example with spring, mainly throw an exception that you can deal with by extending ResponseEntityExceptionHandler #ControllerAdvice
#ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message) {
super(message);
}
}
#Controller
#RequestMapping("/XXXXXs")
public class DoctypesController {
#RequestMapping( method = RequestMethod.GET , value="/xxx")
public ResponseEntity<?> getXXXXXX(HttpServletRequest request) {
if (XXX == null ) {
throw new ResourceNotFoundException("XXXX Not found for);
}else{
response = buildResponse(xxxx)
}
return response;
}
}
#ControllerAdvice
public class XXXXEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = { ResourceNotFoundException.class })
protected ResponseEntity<Object> handleMissingResource(RuntimeException ex, final WebRequest request) {
HttpStatus status = HttpStatus.NOT_FOUND;
return new ResponseEntity<Object>(new Error(String.valueOf(status.value()), status.getReasonPhrase(),ex.getMessage()),status);
}
}
According http specifications, the server must return a error code >= 500 in case of internal error during processing.
If the error is caused because the client did a wrong request : the server must return a error code >= 400 and < 500
Of course, on client side you must take care to handle those errors properly (i.e. displaying a friendly error message or something like that).
You should really use the HTTP Error codes and handle the HTTP error codes using your client-side technology, ie. JavaScript in your case.
For example: given a user who is unauthorised to read/access a Resource, then the 403 error code should be returned to the client. By using the standard HTTP/REST Error codes, you conform to an API that can be understood by any client, whether JavaScript or something else.
With Spring MVC and Rest controllers, it's really easy. Create a simple class for your Exception and annotate the class with the HTTP Error code, e.g. #ResponseStatus(value = HttpStatus.FORBIDDEN) for a 403 error. Then in your Controller, you can throw the exception which would in turn return the HTTP error code.