Parsing json into java objects in spring-mvc - java

I'm familiar with how to return json from my #Controller methods using the #ResponseBody annotation.
Now I'm trying to read some json arguments into my controller, but haven't had luck so far.
Here's my controller's signature:
#RequestMapping(value = "/ajax/search/sync")
public ModelAndView sync(#RequestParam("json") #RequestBody SearchRequest json) {
But when I try to invoke this method, spring complains that:
Failed to convert value of type 'java.lang.String' to required type 'com.foo.SearchRequest'
Removing the #RequestBody annotation doesn't seem to make a difference.
Manually parsing the json works, so Jackson must be in the classpath:
// This works
#RequestMapping(value = "/ajax/search/sync")
public ModelAndView sync(#RequestParam("json") String json) {
SearchRequest request;
try {
request = objectMapper.readValue(json, SearchRequest.class);
} catch (IOException e) {
throw new IllegalArgumentException("Couldn't parse json into a search request", e);
}
Any ideas? Am I trying to do something that's not supported?

Your parameter should either be a #RequestParam, or a #RequestBody, not both.
#RequestBody is for use with POST and PUT requests, where the body of the request is what you want to parse. #RequestParam is for named parameters, either on the URL or as a multipart form submission.
So you need to decide which one you need. Do you really want to have your JSON as a request parameter? This isn't normally how AJAX works, it's normally sent as the request body.
Try removing the #RequestParam and see if that works. If not, and you really are posting the JSON as a request parameter, then Spring won't help you process that without additional plumbing (see Customizing WebDataBinder initialization).

if you are using jquery on the client side, this worked for me:
Java:
#RequestMapping(value = "/ajax/search/sync")
public ModelAndView sync(#RequestBody SearchRequest json) {
Jquery (you need to include Douglas Crockford's json2.js to have the JSON.stringify function):
$.ajax({
type: "post",
url: "sync", //your valid url
contentType: "application/json", //this is required for spring 3 - ajax to work (at least for me)
data: JSON.stringify(jsonobject), //json object or array of json objects
success: function(result) {
//do nothing
},
error: function(){
alert('failure');
}
});

Related

How a rest API will return both Json and XML response depending on the input header?

The code is as follow.Where I am checking the content type extracted from the header then I want to write the code and return the response from the same method.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_XML)
public Response addMessage(Message message , #Context UriInfo uriInfo,
#HeaderParam ("content-type") String contentType) throws
URISyntaxException
{
//Conditional check based on the content type.
if(contentType.equals("application/json")) {
return json;
}else {
return xml;
}
}
How a rest API will return both Json and XML response depending on the input header?
First , your usage of multiple #Produces on same method is incorrect. A String[] can be specified for all types that you wish to produce with #Produces , Annotation Type Produces
And for your main question, I agree with vlumi's comment that ,
You should just return the Response built with the object to return,
and let JAX-RS handle the serialization into XML or JSON, depending on
which the client expects/prefers
i.e. let the framework do it for you depending on Accept header as specified by client as Raj has already mentioned in comments,
You have to pass the request header Accept: application/json or
application/xml
Jersey Multiple Produces

JQuery stringify not working

Simply, I'm trying to parse a List of composite objects passed from Spring controller via ModelAndView object as the following
Spring part
ModelAndView view = new ModelAndView("my view");
List<ActionHistory> histories = myService.getListData();
view.addObject("histories", histories);
return view;
In Jquery i tried couple of alternatives, first used the below line to construct JSON from List:
var list = JSON.stringify('${histories}');
console.log(histories);
the console is returning
"[com.companyname.projectname.domains.ActionHistory#48126327]"
TypeError: invalid 'in' operand a
I also tried from jquery-json by including "jquery.json.min.js" as a suggestion from this topic discussed but getting the same error above Serializing to JSON in jQuery
var histories = $.toJSON('${histories}');
console.log(histories);
Check you contentType in ajax function it should be.
contentType: "application/json"
Also your Spring controller which is handling this mvc call should configure be configired with
produces=MediaType.APPLICATION_JSON_VALUE
e.g. something like
#RequestMapping(value ="/getList", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)

Multipart Request with MultipartFile as Optional Field - Spring MVC

I am using Spring MVC on a J2EE Web application.
I have created a method that bounds the request body to a model like the above
#RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(#Valid #ModelAttribute MyInsertForm myInsertForm) {
// coding..
}
Everything are working great and when i include a property of type MultipartFile in the MyEntityForm, then i have to make the request with content type "multipart/form-data".
Also, everything are working great with this scenario too.
The problem i am facing is that i would like to have the MultipartFile property as optional.
When a client request include a file my method works great but when a client request does not include a file spring throws a
HTTP Status 500 - Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream ended unexpectedly
Is there any way to solve this issue without creating two methods on my controller (one with a MultipartFile and another without)?
I had the same issue and just adding the required=false worked for me; because, I don't send a file all the time. Please find the sample code below,
#RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(#Valid #ModelAttribute MyInsertForm myInsertForm, #RequestParam(value ="file", required=false) MultipartFile file) {
// coding..
}
Give a try by adding
(required=false)
to multipart property in method signature.
When you wish to send one or more files using HTTP, you have to use multipart request. This means that the body of the request will be like the above,
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="text"
text default
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
When you wish to send only data (and not files) you can send them as json, key-value pairs etc.
Spring framework uses the #ModelAttribute annotation when you wish to map a multipart request to an object.
When you have a normal key-value request, you use the #RequestBody annotation.
Thus, you can't have the MultipartFile optional, because you have to use different annotations. Using two different methods, one per request type, solves the issue. Example,
#RequestMapping(value = "/withFile", method = RequestMethod.POST, produces = "application/json")
public ReturnModel updateFile(#ModelAttribute RequestModel rm) {
// do something.
}
#RequestMapping(value = "/noFile", method = RequestMethod.PUT, produces = "application/json")
public ReturnModel updateJson(#RequestBody RequestModel rm) {
// do something else.
}

How to use #RequestBody with a JSONP request?

I am trying to perform an ajax request using the jsonp data type due to cross domain issues in a clustered environment.
I can make jsonp requests to methods mapped with no #RequestBody parameters, but when I do try to implement a RequestMapping with a #RequestBody parameter I get a 415 Unsupported Media Type error.
Usually when I get this problem it is due to some property not mapping correctly between the json object posted and the Java object it is mapped to in Spring. But the only discrepency I can find is that using jsonp it adds a parm named callback and one with the name of an underscore "_"
So I added the tag #JsonIgnoreProperties(ignoreUnknown = true) to my Java object and figured that should solve that, however it is still throwing this error.
Is there anything else I need to do?
EDIT: I am now seeing this stack trace in the debug log output from Spring:
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
$.ajax({
url : 'http://blah/blah.html',
data : { abc : '123' }, (I also tried to JSON.stringify the object but no difference)
dataType : 'jsonp',
success : function(response) {
alert('ok '+JSON.stringify(response));
},
fail : function(response) {
alert('error'+JSON.stringify(response));
}
});
The Spring controller is:
#RequestMapping({ "blah/blah" })
#ResponseBody
public ReturnObject getBlahBlah (#RequestBody MyObject obj) throws Exception {
}
The parameter object is:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyObject {
private String abc;
// getter and setter for abc auto generated by MyEclipse
}
I have a breakpoint on the Controller method which is never hit.
JSONP means that jQuery will create a <script> element with src pointing to your controller URL.
As you can see, this approach doesn't allow you to pass any data in request body, all data should be passed in URL as query parameters. data : { abc : '123' } means that abc=123 is added to the URL.
At controller side you need to use either #RequestParam (to bind inidividual parameters) or #ModelAttribute (to bind multiple parameters into an object):
public ReturnObject getBlahBlah (#RequestParam("abc") int abc) throws Exception { ... }

Consuming JSON request and producing different output

Can you point me to article or explain me how to declare RESTful web service which consumes JSON request and based on parameter inside JSON produces output in different formats, meaning customer can get output in JSON but in pdf also. I'm using Java and RestEasy on JBoss 5.1.
You could map the request on a method returning a RestEasy Response object, using a ResponseBuilder to build your response, setting dynamically the mime type of the response depending on a parameter in your JSON.
#POST
#Path("/foo")
#Consumes("application/json")
public Response fooService(MyObject obj) {
MyResponseEntity entity = MyObjectService.retrieveSomethingFrom(obj);
return Response.status(200).entity(entity).type(obj.isXml() ? "text/xml" : "application/json").build();
}
This way if your MyObject domain object that represent incoming JSON has a parameter xml set to true, then the Response object is parameterized to produce text/xml otherwise it produces application/json. RestEasy should do the rest.
You can use this way
#Path("/")
public class Test {
#Path("/test")
#POST
#Consumes("application/json")
#Produces("text/plain")
public Response addOrderJSON(OrderDetails details) {...}
}

Categories

Resources