Spring WebMVC Exception Handling - rest

I have a global exception handler that extends ExceptionHandlerExceptionResolver that handles exceptions thrown from my #RestController. The JSON payload returned in the response includes an "exception" field. E.g.
{
"timestamp": 01010101010101
"exception": <some exception class>
}
After upgrading from spring-webmvc 4.3.22.RELEASE to 5.0.8.RELEASE, the exception field is missing. Any idea if this is a Spring change, or is this likely my code?

Found it. server.error.include-exception is false by default. Setting it to true re-introduces this behavior.

Related

Vertx not able to handle internal code error to client automatically

I have a verticle which accepts REST request, get data from other verticle through event bus and respond back to client.
vertx.exceptionHandler(event -> logger.error("Vertx exception ", event));
router.get("/api/v1/:param").handler(this::routerHandler);
public void routerHandler(RoutingContext rc) {
vertx.eventBus().request("data", param,
result -> {
if (result.succeeded()) {
logger.info("Request handled successfully");
// intentionally creating exception body() will return String
JsonObject jsonObject = (JsonObject) result.result().body();
rc.response().end(jsonObject)
}else{
logger.error("Request failed");
}
}
When a exception is raised it is printed in exception handler that I setup in vertx instance but after that the vertx is not reporting back the exception immediately to client instead it waits for timeout(30 secs) to occur.
I tried attaching error handler to router object and failure handler to route object but nothing helps to report the exception immediately to client. I know I can have a try catch and report the error in catch block. But I want know if there is any other way to handle this like Servlet or Spring MVC reports back to client even though the exception is not handled in code.
router.errorHandler(500,routingContext -> {
System.out.println(routingContext.failed());
routingContext.response().end("Exception ");
});
router.route().handler(BodyHandler.create()).failureHandler(routingContext -> {
Uncaught exceptions are reported to the context exceptionHandler. By default it prints the exception to the console.
You can configure it but you will not get a reference to the corresponding HTTP request anyway (the exception may come from different things).
Most problems like this are usually found during unit/integration/acceptance testing.
And for the remainders you could set a timeout handler on your router definition to make sure the request is ended before the default 30 seconds.
If you don't want to miss any uncaught exception, you should switch to the Vert.x Rxified API. When using RxJava, any exception thrown will be reported to the subscriber.

How do I avoid duplicate fields in Json request payload ? I'm using Apache Camel with REST

I wanted to parse json request by identifying duplicate fields in the request body. E.g. Assume I have below request.
`"employee": {
"name": "abc",
"name": "xyz",
"id": "6754",
"title": "supervisor",
}`
The employee request above has duplicate name field. ideally during json validation/parsing the second duplicate field takes precedence over first but I want to invalidate this kind of json request. How do I achieve this in Camel REST. Below is the approach that I tried but nothing worked. In myorg.apache.camel.builder.RouteBuilder, I tried configuring DataFormatProperty to use DeserializationFeature FAIL_ON_READING_DUP_TREE_KEY but its not failing. How do I fail the request for invalid json request which has duplicate fields.?
`#Override
public void configure() throws Exception {
restConfiguration().bindingMode(RestBindingMode.json).component("servlet")
.jsonDataFormat(JsonParser.Feature.STRICT_DUPLICATE_DETECTION.name())
.dataFormatProperty("prettyPrint", "true")
.dataFormatProperty("json.in.enableFeatures",
"FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS,FAIL_ON_READING_DUP_TREE_KEY"
+ ",FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE,"
+ JsonParser.Feature.STRICT_DUPLICATE_DETECTION.name())
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_EMPTY_BEANS").enableCORS(true)`
This may come from the fact that Camel is using XStream as default JSON library (see here).
Did you already try to force the use of Jackson library ?

How to handle multiple types of exception from REST

I have a REST resource that can throw many types of exceptions.
In order to retrieve a pretty response when exception happens I did the following:
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(Exception.class)
public ResponseEntity<String> handleError(Exception ae) {
return new ResponseEntity<String>(ae.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
But from clinet side I can't recognize what type of exception was thrown!
I have some Junits with expected exception, and test cases are failing because of that in different modes.
I can add a new class for Error that will contain the exception name: ae.getClass().getSimpleName(), and the message and return it in response.
Is there a cleaner way?
To handle multiple exception types, you could have a look at what Spring MVC does in the ResponseEntityExceptionHandler class. It handles a number of Exceptions and check their types using instanceof.
But from client side I can't recognize what type of exception was thrown!
I can add a new class for Error that will contain the exception name: ae.getClass().getSimpleName(), and the message and return it in response.
You should avoid leaking this information to the client. What if you refactor your code and rename the exception classes? You will break the client code.
Instead, you should translate the exception into something that can be parsed by client (and, of course, document it properly).
Consider, for example, an OutOfCreditException (made up for this example) to indicate that the client's account doesn't have enough credit for a purchase. It could be translated to the following payload, which could easily be parsed by the client:
{
"error": "out-of-credit",
"title": "You do not have enough credit",
"details": "Your current balance is €10, but the items cost €50",
"balance": 10,
"currency": "EUR"
}
For reporting problems in HTTP-based APIs, also consider having a look at the [RFC 7807][4]: It defines defines a simple JSON document format for represeting problems along with the application/problem+json media type.

Send message to a client when an HTTP method not supported

I've created a REST controller the can handle, as usual, GET, POST, PUT and DELETE HTTP requests using Spring MVC. The web server is Tomcat 8.
If a send request, for instance, with HEAD method, the response is an error page from Tomcat with message
HTTP Status 501 - Method LINK is not is not implemented by this servlet for this URI
I have such exception handler:
#ResponseBody
#ExceptionHandler(Throwable.class)
public ResponseEntity<?> exceptionHandler() {
Error error = createError("error_message.unforeseen_error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
But it doesn't catch any error in this case.
Is there a way to send back a message wrapped in JSON object as a response instead of this Tomcat page?
The problem is that SpringMVC does not find any method for HEAD in your controller, so it does not use it and your #ExceptionHandler is not used. It would be used for exception arising inside the controller. Extract from Spring Frameword Reference : You use the #ExceptionHandler method annotation within a controller to specify which method is invoked when an exception of a specific type is thrown during the execution of controller methods (emphasis mine).
To process exception outside of any controller, you must register a HandlerExceptionResolver bean that will replace the DefaultHandlerExceptionResolver provided by default by Spring MVC. You could either directly put the Json String in the response and return null from resolve method (my prefered way), or put the elements in a model and use a view to format the Json.

How to read Wildfly resteasy deserialization error from client?

My Wildfly resteasy service is working fine, or was until I made a code change. No big deal, now I'm getting a deserialization error: "Problem deserializing 'setterless' property ..."
My question is whether there is anyway to get an error message in the client. I'm getting a Status of 400, and I can test that, but I'd like to get any message if possible. Any ideas?
If I get an error in the user code, I can set an error message in the header, but since there is a deserialization problem, the server is throwing a error before getting to any user code.
You can use an ExceptionMapper to handle the response returned to the client. JAX-RS has an exception hierarchy that will map to different responses and status codes. 400 in JAX-RS is a BadRequestException. So you could do something like
#Provider
public class BadRequestExceptionMapper
implements ExceptionMapper<BadRequestException> {
#Override
public Response toResponse(BadRequestException e) {
Response response = Response.status(Response.Status.BAD_REQUEST)
.entity("Sorry I forgot to implement a Setter").build();
return response;
}
}
This isn't a very great example, because BadRequestException is thrown for many other reasons, than just forgetting a setter (or deserialization), but it demonstrates how you can intercept the response after the exception is thrown.
See RestEasy Exception Handling
Jersey User Guider has a better explanation
See Exception Hierarchy