Using jersey jersey.java.net How do I set JSON as the default serialization instead of XML when there is no accept header or .xml suffix is in the URI?
You can assign the quality index to each media type in #Produces annotation. I.e.you can do the following to make Jersey prefer JSON if both XML and JSON are allowed:
#Produces({"application/json;qs=1", "application/xml;qs=.5"})
You should be able to set the #Produces annotation to specify the return format like so:
#Produces( { "application/json" })
How come there is no accepts header?
You can specify preference of generation by specifying media types in your order of preference in the #Produces annotation.
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
In the above code since "application/json" comes first, if no accept header is specified in the request Jersey will default to generating JSON response.
Using qs (as suggested by Martin) makes the preference more explicit, but its a bit more complicated to understand.
Related
I'm building my REST-API with Apache Camel and I use "bindingMode(RestBindingMode.json)" for my restConfiguration with jetty. In one of my Processors I set the "body" of the "out" object with a String that actually is a JSON object. When I set the Exchange.CONTENT_TYPE to "text/plain" the response comes in as expected and can directly be parsed to a JSON object.
{"mockBasicData":"123"}
But when I set the Exchange.CONTENT_TYPE to "application/json" or if I don't set it at all, Camel manipulates the body and escapes it, like it wouldn't already be a JSON object.
{\"mockBasicData\":\"123\"}
Is there a way to avoid that auto-escaping in Camel, as I need the CONTENT_TYPE to be "application/json"?
The typical use of the RestBinding is to specify the marshalling from POJO to json or xml. If I understand correctly what you said, you are converting a json string body to json, right ?
If so, have you tried to set the body of the out object with the JSON Object it-self ?
Please also note the following:
From Camel 2.16.3 onwards the binding from POJO to JSon/JAXB will only
happen if the content-type header includes json or xml. This allows
you to specify a custom content-type if the message body should not
attempt to be marshalled using the binding. This is useful if, for
example, the message body is a custom binary payload.
Adding "bindingMode(RestBindingMode.off)" directly to the route (not to rest()!) solved it for me.
I have a question in regards to the consumes and produces part of the #RequestMapping. I have an endpoint that I want to accept both JSON and XML and return JSON when JSON is passed in and return XML when XML is passed in. Is there anything special that I have to do to make this work?
Sample code is listed below.
#RequestMapping(value = "/something", method = PUT,
consumes = {APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE},
produces = {APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
public SomeObject updateSomeObject(SomeObject acct) {
return doStuff(acct);
}
Will this work the way I'm expecting or do I need two endpoints updateSomeObjectXML and updateSomeObjectJson to handle both cases?
Thanks,
Mike
The article from the Spring blog - Content Negotiation using Spring MVC - provides details on how content negotiation works with Spring MVC, in brief if you want the same endpoint to handle XML and JSON, your mapping is correct, to summarize from the article:
Use path extension - you can send a json to /something.json and xml to /something.xml and expect the same thing on the way back
Use the Accept header, use a value of application/json or application/xml and use Content-Type to specify the submitted media type.
Short answer:
Annotate the method with #ResponseBody, and the method parameter with #RequestBody, and it will work (no need for 2 methods).
Explanation:
First, produces and consumes attributes are used to narrow the mapping types. By default the first HttpMessageConverter found, that matches the media type requested, will be used.
Second, client requests a media type by giving the media type in:
- Accept request header
- URL sufix (http: //....//some .xml => "application/xml" media type requested)
- URL format parameter (.../some?format=xls)
Third, produces in combination with #ResponseBody will produce the object in the requested media type (nice for GET requests, when you need to send something back to the client), and consumes in combination with #RequestBody will consume the object with the requested media type (nice for POST requests, when you need to get something from the client).
Four, when #ResponseBody not used, HttpMessageConverters are not used. Rather ViewResolvers kick in and produce a view (HTML, PDF...), and the return type should follow the rules that accompany ViewResolvers (check default view resolver and InternalResourceViewResolver for more).
Hope it helps.
Other sources:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#consumes--
http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
Well,
consumes/produces takes String[] as a parameter (see RequestMapping from Spring's documentation) so I believe it will work. You can also try headers = "content-type=application/json,application/xml".
So I understand that you are specifying the type, but why? Under what conditions would it matter. For example, if I have the following method, and I comment out the #Produces annotation, it still returns JSON.
#GET
#Path("/json")
//#Produces({MediaType.APPLICATION_JSON})
public String getJson(){
return toJson(getResults());
}
The API doc says 'If not specified then a container will assume that any type can be produced.' So why would I not want the container to assume that?
I think it depends on your JAX-RS implementation but here's Jersey's explanation of their #Produces annotation: https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e1809
Basically, it's up to the client to determine what content type the server should spit back.
If the client supports more than one content type, you can sometimes specify the priority of content types to return, for a given method:
#Produces({"application/xml; qs=0.9", "application/json"})
In the above sample, if client accepts both "application/xml" and "application/json" (equally), then a server always sends "application/json", since "application/xml" has a lower quality factor.
If a client requests your JSON only resource with an Accept: application/xml; header then strictly speaking the server should return a 406 (not acceptable) status code, not the JSON string.
If you use the #Provides annotation, the container should handle this case for you and that is why you should use it.
I am currently working on a project which was maintained by some other team and now i need to maintain it. While i was going through the project i found some thing below:
In jax-rs controller it was annotated by #Consumes(MediaType.APPLICATION_JSON) but the method takes request body as String rather than JSON. Then what is the use of the annotation? Does it help in content negotiation anyway?
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createCake(final String requestBody){.......}
How it is converting a JSON body to string?
My technology stack if it anyway helps to answer:
JAX-RS
Spring 3.2
Jersey 2.4
The #Consumes serves the following purpose. It restricts the mapping for your handlers. For example, you may have two handlers for the path /resource, one mapped to consume XML and the other mapped to consume json. The dispatcher will choose the right one based on the request's content-type.
The parameter type can be anything as long as there is an appropriate converter for the specified media type to the parameter type itself. In this case, there's very likely a converter from any media type to String.
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.