How to handle Incorrect JSON syntax in Spring MVC - spring-mvc

I have a spring MVC Project, wherein I need to handle incorrect JSON syntax.
Spring MVC throws an error as text/html, which looks like:
Apache Tomcat/7.0.47 - Error report HTTP Status 400 - type Status reportmessage description The request sent by the client was syntactically incorrect.Apache Tomcat/7.0.47
However I want to throw my own exception in JSON format.
Is there any way to do it?
Thanks

I just ran into this as well, here's what I found to fix it:
The Spring MVC docs reference HttpMessageConverter as responsible for converting a #ResponseBody. For JSON, you're likely using a MappingJackson2HttpMessageConverter, which when attempting to convert a message can throw a HttpMessageNotReadableException.
If you have some form of exception handler for that, you can intercept the 400 response.

You can debug to see which Exception is actually thrown (might be a TypeMismatchException or something like that). Then, you can specify an error handler in your controller like
#ExceptionHandler(TypeMismatchException.class)
public String handleTypeMismatchException(TypeMismatchException ex) {
}
Now, in this controller method you can do whatever you want, like passing it the model, request, response etc. You can send to a view, redirect or in your case use a ResponseBody or however else you would like to serve your JSON error.

Related

How can I return a custom reponse for a bean validation error under Open Liberty?

We are using beanValidation-2.0 and cdi-2.0 under Open Liberty 20.0.0.3. This works fine in that Open Liberty returns a 400 Bad Request response containing the bean validation error message when a a bean validation error is detected. I would like to update our application to instead return a custom response when Open Liberty detects a bean validation error. Is there a way that I can somehow "intercept" the bean validation error (or the Open Liberty generated response) and return my own custom response?`
Usually when you get a validation error, a ConstraintViolationException is thrown and you should be able to catch that and create your own response.
If you're using JAX-RS, you might want to do this by creating and registering an ExceptionMapper to handle this type of exception and turn it into a response. There's an example here.
You might be able to do this with a custom MessageInterpolator.
It can be specified via the message-interpolator element of validation.xml.

IExceptionHandler does not handle UnsupportedMediaTypeException

I have implemented an exception handler (IExceptionHandler). Its HandleAsync method is called when exceptions are thrown inside controllers.
However, when a wrong content-type is passed with the request and an UnsupportedMediaTypeException is thrown in the formatter, my handler is not called. Instead the default error message is returned
{
"Message": "The request entity's media type...
"ExceptionMessage": "No MediaTypeFormatter ...
...
}
I would like to handle ALL exceptions. What am I missing here?
You need to catch it with a global ExceptionFilterAttribute, and filter HttpResponseException, not UnsupportedMediaTypeException.
E.g.
httpConfiguration.Filters.Add(new MyHttpResponseExceptionFilterAttribute());
It turns out that UnsupportedMediaTypeException is actually wrapped up in an HttpResponseException by the time it hits the WebApi pipeline.
HttpResponseException is not intercepted by IExceptionHandler, because it is designed to transport an HttpResponsMessage out to the client. The UnsupportedMediaTypeException is automatically wrapped into an HttpResponsMessage by the framework, and thrown in a HttpResponseException. The message you see in the HTTP response says "UnsupportedMediaTypeException", but that is actually just the Content of the HttpResponsMessage (HttpResponseException.Response.Content).

Spring MVC Returns Response Before Completion of Controller Method

I have the following method which is returning an incorrect response to the browser before the method is even complete. This is in Spring 3.2.
#RequestMapping(value="/process1/createEditContract/validate", method=RequestMethod.POST)
public #ResponseBody StatusResponse validateProcess1(#ModelAttribute("contractEditForm") #Valid Process1CreateEditContractDTO dto, BindingResult bindingResult) {
StatusResponse response = new StatusResponse();
response.setSuccess(true);
if (bindingResult.hasErrors()) {
log.debug("Errors found. Processing status response");
response.setSuccess(false);
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fe: fieldErrors) {
response.getMessages().add(messageSource.getMessage(fe, null));
}
}
return response;
}
StatusResponse is a simple object that a javascript function in the JSP reads to generate a Javascript alert stating whether the action was successful or errors occurred. The method makes it all the way through, but as soon as it tries to write the response, I get this:
java.net.SocketException: Software caused connection abort: socket write error
I've been stuck for a day now, any help would be appreciated.
UPDATE
I rolled back from Spring 3.2 to Spring 3.1, and the wording of the error message changed enough to give me more information.
Basically, I'm getting now seeing this:
IllegalStateException: Response already committed
What I don't see is what is causing the response to commit so quickly. Maybe a conflict with the OpenSessionInViewFilter?
This error can occur when the local network system aborts a connection, such as when WinSock closes an established connection after data retransmission fails (receiver never acknowledges data sent on a datastream socket).". See this MSDN article. See also Some information about 'Software caused connection abort.
To prove which component fails I would monitor the TCP/IP communication using wireshark and look who is actaully closing the port, also timeouts could be relevant.
The javascript runs in browser, and your controller runs on server. You cannot pass a complex object from the controller to the javascript without converting it to a textual format such as xml or json.
So you should :
choose a format (say json)
add a produces="application/json" in your RequestMapping annotation
do generate json in your controller method

Propagating AccessDeniedException in Spring Security

In my web application I am using Spring Security and Spring MVC.
I have secured a couple of methods with #Secured annotation and configured Spring Security in such a way that when one of those methods is accessed without the proper role, the user is taken to the login page. However, I do not want that behaviour when the offending request comes from Ajax, so I implemented the custom #ExceptionHandler annotated method to determine the request's context.
This is my exception handler:
#ExceptionHandler(AccessDeniedException.class)
public void handleAccessDeniedException(AccessDeniedException ex, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (isAjax(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else {
throw ex;
}
}
This way I can both handle the exception myself (for example, log an attempt of accessing the #Secured method) and then let Spring do its part and redirect the user to the login page by rethrowing the AccessDeniedException. Also, when the request comes from Ajax I set the response status to SC_UNAUTHORIZED and handle the error on the client side.
Now, this seems to be working fine, but I am getting the following ERROR each time I rethrow the exception from the handleAccessDeniedException method:
ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke #ExceptionHandler method: public void app.controller.BaseController.handleAccessDeniedException(org.springframework.security.access.AccessDeniedException,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception
org.springframework.security.access.AccessDeniedException:
at app.controller.BaseController.handleAccessDeniedException(BaseController.java:23)
at app.controller.BaseController$$FastClassByCGLIB$$8f052058.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
(...)
I have not added any exception handling specifics to spring xml configuration files.
I do not see any issues with the app itself, but the error is there and since I am quite new to Spring MVC and Spring Security, I am guessing that I am not doing this properly. Any suggestions? Thanks!
Your exception handler isn't supposed to throw another exception. It's supposed to deal with it and send a response. It's a good idea to check the code if you get an error from a class to see how it behaves.
For the non-ajax case, you'd be better to redirect the response to the login page, if that's what you want. Alternatively, you can customize the AuthenticationEntryPoint used by Spring Security instead and omit AccessDeniedExceptions from MVC handling. The behaviour would essentially be the same as the defaul LoginUrlAuthenticationEntryPoint but you would extend it to return a 403 when an ajax request is detected.

Performing redirects in ServiceStack

I'm attempting to build a service in ServiceStack whose sole responsibility will be to interpret requests, and send a redirect response. Something like this:
[Route("/redirect/", "POST")
public class Redirect : IReturnVoid
{
public string Something { get; set; }
}
public class RedirectService : Service
{
public object Post(Redirect req)
{
// make some decisions about stuff
return new HttpResult(){ StatusCode = HttpStatusCode.Redirect, Headers = {{HttpHeaders.Location, "place"}}};
}
}
I did initial testing using fiddler, setting a content-type of application/json and creating an appropriate request body.This did exactly as expected: the service request gave a 302 response and redirected to the expected location.
I've also tested this by using a basic Html form post, with an action of http://myserviceuri/redirect/, which also works as expected and redirects appropriately.
However, i've hit an issue when attempting to use the SS c# client to call the same service. If I call the following code in an aspx code behind or an mvc controller
var client = new JsonServiceClient("uri);
client.post(new Redirect{Something = "something});
I get a 500 and the error message:
The remote certificate is invalid according to the validation procedure.
Which makes sense as it's a development server, with a self-cert. But I get the feeling that, as I can call the service successfully by other means, that this is a red herring.
Should I be using a different type of c# client to make the request, or setting any more custom headers, or something else? Am I fundamentally not understanding what i'm trying to do?
Please let me know if more info is needed. Thanks.
What's happening here is that the JsonServiceClient is happily following the redirect, doing more than what you've expected it to do.
I'll reference a related question and answer for posterity ( - hopefully you've resolved this issue a long time ago...).
POST to ServiceStack Service and retrieve Location Header
Essentially you'd use .net's WebRequest or the ServiceStack extensions mentioned in the answer to see the redirect and act as you see fit.

Resources