Spring MVC Response already committed Issue - spring

#RequestMapping(value="/getStats/{requestData}" , consumes=MediaType.APPLICATION_JSON_VALUE , method=RequestMethod.GET)
public void testRequest(
#PathVariable (value="requestData") GetStatsRequestBean getStats){
System.out.println("inside (testRequest)");
System.out.println(getStats);
}
In server log am getting
SRTServletRes W WARNING: Cannot set header. Response already committed.
And my app url is..
http://myhost:9080/myapp/getStats/{"startDate":"2013-10-05","endDate":"2013-10-05"}

Trying to set a response header after the response is committed causes this warning. The code you shared does not seem to do this. Are you sure you do not have any filter configured which tries to do this ? Your controller handler method return type is void which implies that you intend to generate the response yourself by using http servlet response object which needs to be provided in tehemethod parameter so that Spring can inject it and you can use this. As you have not provided the httpservlet response object in parameter, the actual view served would be implicitly determined by through a RequestToViewNameTranslator configured in your context.

Related

Spring MVC - Error handling with redirect if download not possible

in my Spring Boot application you can download some documents, by pressing a button. This leads to the following user experience: If the user presses the button, either a download is triggered or nothing happens.
Currently, the backend is either returning the bytes or 404:
#GetMapping("/download")
public ResponseEntity<byte[]> download() {
Optional<byte[]> data = service.getDocumentData();
return data.map(bytes -> new ResponseEntity<>(bytes, headers(), OK))
.orElseGet(() -> ResponseEntity.notFound().build());
}
Now we want to achieve, that the user is redirected to an error page, if no file can be downloaded.
With Spring MVC I would just return the error template like
public String notFound() {
return "error/404"; // the custom template
}
But now I need to mix two different concerns. Returning template or returning a ResponseEntity. For this i stumbled above the following answer, which uses Generics. However, I don't think its a good practice. So i thought about other ways.
My first idea was to use HTTP location header for redirecting on the frontend side, but I never used it before. Do you think this is a good way? Do you have other ideas?
Suggestion 1:
In the download() method, add HttpServletResponse response as the parameter and call response.sendRedirect("http://somewhere/404.html"); when the document requested is not found.
In addition, you can also change the status code in the response as response.setStatus(HttpServletResponse.SC_NOT_FOUND);
Suggestion 2:
Throw a custom exception, for e.g. FileNotFoundException and handle the exception in the #ExceptionHandler to return the error page in the ResponseEntity.
Refer - https://howtodoinjava.com/spring-core/spring-exceptionhandler-annotation/

Get headers from #RequestHeader vs HttpServletRequest

What's the difference between read header data from #RequestHeader annotation vs HttpServletRequest?
The advantage of using Spring #RequestHeader is that it will automatically throw an exception like
HTTP Status 400 - Missing request header 'X' for method parameter of type, if the header is NOT sent in the input request (by setting required=true). An example usage shown below:
#RequestMapping(method=RequestMethod.GET)
public String users(#RequestHeader(required=true)String myHeader, Model model) {
//your Code
}
You can also set the default value for the header if you use #RequestHeader, you can refer here
We need to manually check the condition for header value !=null, throw the exception or set the default value, if you use HttpServletRequest, which will make your code verbose.
There is no difference in Performance. It is more convenient to use #RequestHeader than HttpServletRequest.getHeader().
This is similar to #RequestParam and HttpServletRequest.getParameter().
Spring has done the work of converting the request Headers, Parameters to method Parameters so that you can avoid boilerplate code.
There is a Spring written MethodArgumentResolver named RequestHeaderMethodArgumentResolver which in fact uses HttpServletRequest.getHeader() to get the header.

Spring MVC - HTTP status code 400 (Bad Request) for missing field which is defined as being not required

I have Spring MVC application with this controller method.
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addNumber(#RequestParam(value="number", required=false) Long number) {
...
return "redirect:/showAll/";
}
In my JSP I have a standard HTML form which is posting a value named "number" to the controller method above. However, if I leave out the value (do not enter anything into the text field) and POST the data to the controller, before the controller method is called my browser shows
HTTP Status 400 - Required Long parameter 'number' is not present
although the controller method annotation clearly defines the "number"-parameter as not required.
Does anyone have a slight idea of what could be going on?
Thank you.
PS: The exception that is being thrown is as follows:
org.springframework.web.bind.MissingServletRequestParameterException: Required Long parameter 'number' is not present
EDIT: This is a Spring 3.2.3.RELEASE bug ( see here). With version 3.1.4.RELEASE I do not have this problem anymore.
I came across the same situation, and this happens when your parameter is present in the request with an empty value.
That is, if your POST body contains "number=" (with empty value), then Spring throws this exception. However, if the parameter is not present at all in the request, it should work without any errors.
My problem was that some of the headers in a request I was sending with Postman were not present (were unchecked):
When I checked back the Content-Length header, the request worked fine (200 OK response).

Jersey: Returning 400 error instead of 500 when given invalid request body

I'm using Jersey's integrated Jackson processing to transform incoming JSON to a POJO, e.g.:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response newCustomer( CustomerRepresentation customer)
{
...
}
If a client sends JSON with invalid fields Jersey currently returns a 500 Internal Server Error. Instead, I'd like to return a 400 Bad Request, preferably with some meaningful detail indicating which fields are in error.
Any insight into how this could be accomplished? (At least returning a generic 400 instead of the completely inappropriate 500?)
Update:
Here's the exception being generated server-side, before my handler is invoked:
javax.servlet.ServletException: org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "this_isnt_a_known"_field" (Class com.redacted....), not marked as ignorable
I was finally able to work around this problem by implementing an ExceptionMapper to catch the UnrecognizedPropertyException thrown by Jackson and map it to a 400 Bad Request response:
#Provider
public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<UnrecognizedPropertyException>
{
#Override
public Response toResponse(UnrecognizedPropertyException exception)
{
return Response
.status(Response.Status.BAD_REQUEST)
.entity( "'" + exception.getUnrecognizedPropertyName() + "' is an unrecognized field.")
.type( MediaType.TEXT_PLAIN)
.build();
}
}
I tried mapping status 500 to status 400 with HolySamosa's answer but the exception was not caught by this mapper, and status 500 was still being returned.
After debugging I found that JsonParseException is being thrown and not UnrecognizedPropertyException. This is because I was sending some garbage text (that was not JSON at all).
When I sent a proper JSON from client side, with format that was not appropriate for my DTO on the server side, then I got UnrecognizedPropertyException.
So there are two cases for this:
when you send garbage that is not JSON and
when you send JSON, but it is not a match for your DTO class.
Now I am returning status 400 for both.
In dropwizard land there is an ExceptionMapper called JsonProcessingExceptionMapper that has similar functionality as to what you are looking for. Maybe you can use that for inspiration on how to address your specific issue in a non-dropwizard world.
I've had this same problem... Unfortunately, there's no good way that I know of to intercept the Jackson exception and generate your own error code.
One option you have is to use #JsonIgnoreProperties and then strictly validate the deserialized object. This won't tell you if your sender transmitted junk, but if they missed required fields, you'll catch that.
I cannot find any way to access the actual JSON passed in, other than creating an #Provider class to trap the JSON, validate it, then pass it to Jackson for deserialization.

Validate request headers with Spring validation framework

Is it possible to use the Spring validation framework with Spring MVC to validate the presence and value of an HTTP request header?
To check the presence of a request header, you don't need the validation framework. Request header parameters are mandatory by default, and if a mandatory header is missing in a request, Spring MVC automatically responds with 400 Bad Request.
So the following code automatically checks the presence of the header "Header-Name"...
#PostMapping("/action")
public ResponseEntity<String> doAction(#RequestHeader("Header-Name") String headerValue) {
// ...
}
... and if the header shall be optional, the annotation would need to be replaced by:
#RequestHeader(name = "Header-Name", required = false)
To check the value of a request header, the Spring validation framework can be used. To do this, you need to
Add #Validated to the controller class. This is a workaround needed until this feature is implemented.
Add the JSR-303 annotation to the request header parameter, e.g.
#RequestHeader("Header-Name") #Pattern(regexp = "[A-Za-z]*") String headerValue
Note however that this will result in a 500 in case of an invalid header value. Check this question for how to also get the correct status code (i.e. 400) for this case.
I don't see how this would be possible, since the validation framework only operates on your domain objects, not on the HTTP request itself. Specifically, the Validator interface doesn't specify any methods that take the HttpServletRequest object, which is what you'd need to have access to in order to grab the headers and test them.
Using the validation framework feels like the wrong solution to whatever problem you're trying to solve, especially since it's hard to know how there'd be a unique HTTP request header for a given form submission. Are you looking to test for an HTTP header that should always be present in requests to your app? Then you might want to consider implementing a HandlerInterceptor, which will intercept and process all requests to pages that you've mapped in any HanderMappings. Are you looking to test for an HTTP header that should always be present in any page view of your app? Then you'd want to implement a Filter, which operates outside of the context of Spring MVC.

Resources