Why do I need to add #ResponseBody to my controller action? - java

According to Spring documentation, this annotation indicates that a method return value should be bound to the web response body. I understand that, and I've been using this for my ajax calls. However, I recently came across code that doesn't use the annotation.
So I guess my question really is why it works without the annotation?

Without the annotation, a different process takes place. Depending on the return type (you can find the defaults in this document) the response will be generated differently.
For example, if your return type is String, then, by default, the return value will be resolved as a View name, a ViewResolver will try to resolve and create a View object, and a RequestDispatcher will forward/include/redirect to it (ex. a jsp) so that the Servlet container can handle generating the response.
The actual interface that handles the return type is HandlerMethodReturnValueHandler and there are many implementations for each type. See here for more information.

Related

The Model parameter in #RequestMapping method

Currently I am learning Spring specifically the Spring MVC part and I stumbled on thing I don't quite understand how does it work.
#RequestMapping("/foo")
public String foo(Model model){
// code here
return "foo";
}
The method above annotated with #RequestMapping receive the parameter with class Model and sometimes ModelAndView.
What I don't understand is where the Model parameter comes from and how the flow is from the spring configuration class (Such as WebConfig.java) which use the ComponentScan and a Bean of InternalResourceViewResolver.
I've been looking for sources and I don't find anything helpful for me, even the documentation, which makes me to ask here for the first time.
A direct explanation will be really helpful, or if there are any sources can be put the link here.
If it is from the documentation please mention which part/section it is because I might miss one or two thing.
The method above annotated with #RequestMapping receive the parameter
with class Model and sometimes ModelAndView.
The below post explains in detail about ModelAndView and Model
When to use ModelAndView vs Model in Spring?
where the Model parameter comes from
A Controller is typically responsible for preparing a model Map with data and selecting a view name but it can also write directly to the response stream and complete the request. View name resolution is highly configurable through file extension or Accept header content type negotiation, through bean names, a properties file, or even a custom ViewResolver implementation. The model (the M in MVC) is a Map interface, which allows for the complete abstraction of the view technology. You can integrate directly with template based rendering technologies such as JSP, Velocity and Freemarker, or directly generate XML, JSON, Atom, and many other types of content. The model Map is simply transformed into an appropriate format, such as JSP request attributes, a Velocity template model.
Reference - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-arguments

Can you specify preferred default media type for a single path in Spring MVC?

I have a Jersey application which has been converted to Spring MVC. One piece of functionality that I don't see a way to port directly over is the ability, per path, to specify the preferred media type if none is specified. In Jersey, I could specify the "qs" property on the media type, and it would use that to determine which response type to send if none were specified (or if multiple options were specified in the Accept header, I believe this value was multiplied by the quality scores specified).
#Produces("application/json")
#GET
#Path("/some/path")
public Response preferredResponseType() {
//Implementation goes here
}
#Produces({"application/schema+json;qs=0.9"})
#GET
#Path("/some/path")
public Response otherResponseType() {
//Implementation goes here
}
In this example, if I do a GET request against /some/path with no Accept header, it will return the application/json response.
I don't see any easy way to do this in Spring MVC, particularly not if I want to restrict the default to applying to just that one endpoint (there are other endpoints in the app that should have a different preferred default). I do see that there is a way to globally set a default content type (per the "defaultContentType" and "defaultContentTypeStrategy" methods in ContentNegotiationConfigurer), but that does not easily address the per-path use case.
Is there an easy way to achieve per-path media type defaults different from the application global default?
Spring issue 19050 requests this functionality. Per the conversation there, it looks like there is no simple way to declaratively specify the default content type to use. Furthermore, the Spring team has closed the issue with a decision not to implement this functionality.
The "defaultContentTypeStrategy" allows to provide your own ContentNegotiationStrategy to use. It has access to the full request so you can make path based decisions possibly with the an AntPathMatcher to support patterns easily.

Spring #RequestBody annotation in Restful web service

Thanks to #RestController I don't need to add annotation #ResposneBody, cause spring knows that it is rest controller, and he will not generate view, but instead it will return json object.
Unfortunately there is one more annotation related to this topic. It is #RequestBody, when controller method accept json object as a parameter. And it will have to be pointed before that parameter.
My question is there a way to get rid of that annotation (#RequestBody).? If my controller is rest controller (#RestController instead of regular #Controller) it should be demanded from spring?
No, you'll have to specify #RequestBody. A Java method can have only a single return value, and so the #ResponseBody is unambiguous, but there are multiple possible ways that mapped controller parameters might be interpreted (in particular, using #ModelAttribute with form encoding is a very common alternative to #RequestBody with JSON), and you'll need to tell Spring how to map the incoming request.

#Produces annotation in JAX-RS

My service method Produces one of this MediaTypes it may produce pdf or excel file or other.
#Produces({"application/pdf","application/vnd.ms-excel"...
My Question
My service returns response type with application/pdf always even if it produces excel. Why?
Than I rearranged MediaTypes.
#Produces({"application/vnd.ms-excel","application/pdf",...
Now it's giving type application/vnd.ms-excel for all responses,again Why?
I am using com.sun.jersey API for client and getting type by the use of
clientResponse.getType()
Probably I think I misunderstood the concept of #Produces annotation.
Please Clarify.
Following is code of my Service method.
response = Response.ok((Object) file);//file is Object of File
response.header("Content-Disposition","attachment; filename="+filename);
//filename can be a.pdf b.xlsx etc
return response.build();
JAX-RS methods should base the preferred content type on the value of the Accept header of your request. Failing that, it should default to the first specified.
While the JAX-RS spec is somewhat vague on the subject, the Jersey documentation is very clear in describing the selection mechanism.
As it said in the documenation:
#GET
#Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
The doGetAsXmlOrJson method will get invoked if either of the media types "application/xml" and "application/json" are acceptable. If both are equally acceptable then the former will be chosen because it occurs first.
Also, you can use quality factor for specifying which media type is more preferable:
#Produces({"application/xml; qs=0.9", "application/json"}).
In any way, if you want to be sure about which media type is used, you should divide your methods into two different signatures.
The #Produces annotation is used by the JAX-RS implementation to bind the incoming request to one of your Resource Methods, based on the accept header of the request.
You can set the exact type of the response in the returned Response object using ResponseBuilder#type(MediaType) if you want to enforce one media type in particular.
If you want to match the accept header of the incoming request ("application/vnd.ms-excel" vs "application/pdf" in your case), you can retrieve that header by adding a parameter annotated with #HeaderParam("accept") in your Java method.
HTH.

Is there a way to access HttpRequest type inside a #Controller method

I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/

Categories

Resources