Title: Simple restful JSON POST with java as server and jquery as client
Tags: java;jquery;json;ajax;restful-architecture
Question: Before I ask my question I have to say that I have read more than 20 questions and articles about this problem and none of them could solve it.
My problem is I have a restful server in java like this:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final String stringRequest, final HttpServletResponse response)
try
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
catch (final Exception exception)
LOG.debug("Exception Thrown [downloadByCode]", exception);
And I have tried different ways to send a json to this server with jquery (but all of them create errors):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form
urlencoded;charset=UTF-8' not supported", "type" :
"HttpMediaTypeNotSupportedError"
So I tried to fix it by adding contentType:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class
[class java.lang.String]: null; nested exception is
javax.xml.bind.JAXBException\n - with linked
exception:\n[java.lang.NullPointerException", "type"
:"HttpMessageConversionError"
I tried to send json object directly instead of JSON.stringify and it gives the same 400 error.
I tried to add different consumes to the @requestMapping but still no luck.
I tried to define my own class instead of JsonNode but it does not change anything.
Any ideas?
Comment: Have you tried changing your @RequestBody parameter type to Map or creating a class with a single "name" property and using that as the type (as suggested by Vinh Vo)?

Comment: Did you create InputData as an inner class as the error states?

Comment: As stated in the error, you'll need to declare "public static class" in order to get it working. As for the map, that is how you would access it. I would not leave it that way permanently, only to test if it's working. The proper way to use @RequestBody is to create a class to hold the deserialized JSON data.

Comment: You probably need to use a POJO class then as suggested by Vinh Vo. Declare the class static or put it in a separate file and you should be all set.

Comment: Bounty should go to Vinh Vo, his answer was correct and first. The class only needs to be static because you made it an inner class, if you create the class in its own file, the static modifier is unnecessary.

Comment: @NTyler, I never tried Map, I am going to try it now. Thank you for the suggestion

Comment: Vinh Vo method creates the following error: `Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported.`

Comment: @NTyler, yes, should not I?

Comment: if I use map then I can access "value" with `(String) stringRequest.get("name")`. Is it correct?

Comment: @NTyler, I get this error for map: `Could not instantiate JAXBContext for class [interface java.util.Map]: null; nested exception is javax.xml.bind.JAXBException\n - with linked exception:\n[java.lang.NullPointerException]`

Comment: @NTyler, Add static to my bean class solved the problem!! I really appreciate your help.

Comment: @NTyler, do you want to post it as an answer to get the bounty?

Here is the accepted answer: The final answer is a combination of a number of answers/comments in this question that I am going to summarize them here:
1- You have to make sure you have an appropriate json converter in your spring config such as MappingJacksonHttpMessageConverter (credits to @java Anto)
2- You have to create a POJO class with same structure as your json object (see @Vinh Vo answer)
3- Your POJO class cannot be an inline class unless it is a static class. It means it should have its own java file or it should be static. (credits to @NTyler)
4- Your POJO class can miss parts of your json object if you set it appropriately in your object mapper (see @Aman Tuladhar answer)
5- Your ajax call requires contentType:"application/json", and you should send your data with JSON.stringify
Here is the Final code that is working perfectly:
public static class InputData
private String name
public String getName()
return name;
public void setName(final String name
this.name = name;
@RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final InputData request, final HttpServletResponse response)
try
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
catch (final Exception exception)
LOG.debug("Exception Thrown [downloadByCode]", exception);
And it is the jquery Ajax request:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });

Here is another answer: Looking at your errors, it's clear that you have configured 'Jaxb2RootElementHttpMessageConverter' or similar XML converter in your spring configuration. And since you have registerned an XML converter, the @RequestBody and @ResponseBody work based on the registered message converters.
So, to solve your problem, go with a JSON message converter such as 'MappingJacksonHttpMessageConverter'. Once you register a JSON message converter, create a bean class to hold your json data and use it with RequestBody as below:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
Update 1:
Since you have defined multiple message converters, Spring tries to use the first one available by default. In order to use specific message converter(in this case Jackson converter), you should specify 'Accept' header from client like below:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })
Comment for this answer: Thank you for the response, I already have json converter:
Comment for this answer: And I created the bean class with same structure as my json `{"name","value"}` but I get this error: `Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported`
Comment for this answer: I think you are absolutely right. I defined three message converters ``, ``, and ` `. Now the question is why it is using JAXB instead of jackson while my contentType is application/json.
Comment for this answer: I noticed that my json structure class was an inline class and it should be `static`. After adding `static` to my class now spring choose the correct converter and the `accept` tag is unnecessary. I appreciate your effort to solve this issue.
Comment for this answer: The actual issue is it tries to use JAXB converter when it's supposed to use Jackson converter.

Here is another answer: Change your method downloadByCode() return type to String and then return the String
Response body will automatically convert the returned String to JSON and then use the data appropriately
Comment for this answer: It never arrives to response phase. It generates error when it tries to load json as input.

Here is another answer: First of all If you are using maven you should add dependency for jackson
<dependency&gt;
<groupId&gt;com.fasterxml.jackson.core</groupId&gt;
<artifactId&gt;jackson-databind</artifactId&gt;
<version&gt;2.4.1</version&gt;
</dependency&gt;
or you can download the jar and put it in our project class path (you can use other mapper as well)
then you should create a model or DTO class where you can map your json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
THEN you controller
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public Data downloadByCode(@RequestBody final Data data, final HttpServletResponse response)
//your code
return data;
AJAX CALL
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(Optional)You can override behavior by telling object mapper not to fail on missing properties by defining the bean as follows:
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/
Comment for this answer: Thank you for your help. This answer is how everything should work "ideally"! but, it generates error in my environment.

Here is another answer: With Jersey api you can try just:
@POST
public void downloadByCode(String stringRequest)
and I think you'll find the body of your post in stringRequest.
Comment for this answer: Thanks, maybe I give it a shot if I could not solve it without an additional API.

Here is another answer: try @RequestBody final Map<String, String&gt; stringRequest
also you will need consumes = "application/json" on the @RequestMapping because you have that in your AJAX call
You will get 400 if spring doesn't like the format in which you send your ajax - I've had so much trouble with this in the past and it seems better to just ignore header types and content types unless necessary
Comment for this answer: You also need the consumes part of my answer (or just take it out of your ajax call) - does that work?
Comment for this answer: Thank you for the answer. I have changed my request body to this:
`public void downloadOrdersByCode(@RequestBody final Map requestMap, final HttpServletResponse response)`
But, I am still getting same 400 error as above

Here is another answer: Delete the @ResponseBody on your downloadByCode method
Comment for this answer: Nothing changed, I think the problem is related to getting json as input. The output part looks fine.

Here is another answer: Please try to create new class :
public class InputData{
private String name;
public String getName(){
return name;
public void setName(String name){
this.name = name;
public void downloadByCode(@RequestBody InputData stringRequest, final HttpServletResponse response)
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
Comment for this answer: Thank you for the suggestion but I am getting this error: `Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method.  Note that non-static inner classes do not have zero argument constructors and are not supported.`

Here is another answer: You can take request body as string with usage of org.springframework.http.HttpEntity<String&gt; as request type, here is example with your code as base:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(final HttpEntity<String&gt; request, final HttpServletResponse response)
try
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
catch (final Exception exception)
LOG.debug("Exception Thrown [downloadByCode]", exception);
But maybe it will be better to use also String as return type, if you are planning to return result as string value, like this:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public String downloadByCode(HttpEntity<String&gt; request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
I made simple application using Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven and JDK >= 1.7.
#clonning repository with sample
git clone douglaspeter@example.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
After application will be started you can open http://localhost:8080 and you will see html page with simple usage of JQuery to send POST requests, text of request and response will visible on html page, in controller I added two handlers, first with usage of HttpEntity and second with usage of POJO.
Controller: SampleRestController.java
HTML page: index.html
Project: https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text
Comment for this answer: Try to use in request from js option `contentType: "application/json"` as you did previously. `$.ajax({ url: "/downloadByCode", contentType: "application/json", type: "POST", data: '{"name":"value"}' }).always(function (data) { alert(data); });`
Comment for this answer: I'm agree with you, most probably something is wrong with your configuration of spring, and unfortunately it's hard to say what exactly is wrong without ability to look on it. But to show you how it is easy to implement proposed by me solution for handling REST requests with Spring Boot, I created sample application, you can find it in updated answer, I verified it on my local env and it works. Also I saw same error `Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported` only until I added usage of `contentType: "application/json"` and after that it works fine.
Comment for this answer: I am going to give it a try! Thanks :)
Comment for this answer: I get this error: `Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported`
Comment for this answer: I use this jquery ajax: `$.ajax({ url:"/downloadByCode", type:"POST", data: JSON.stringify({"name":"value"}) });`
Comment for this answer: I tested it with "application/json" contentType and I get this error: `Could not instantiate JAXBContext for class [class java.lang.String]: null; nested exception is javax.xml.bind.JAXBException\n - with linked exception:\n[java.lang.NullPointerException]`
Comment for this answer: I think something is wrong with my spring :/ Why it does not support `application/x-www-form-urlencoded;charset=UTF-8` ??

Here is another answer: I am not that well versed with java but as much as I know your java code must be something like this.
public class downloadByCode{
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(@QueryParam("paramater1") final String parameter 1, @Context HttpServletRequest httpRequest) {
If this not helps you can keep you code somewhere and share it.
Comment for this answer: I think this code is based on GET method, I want to get JSON object (or JSON string) with POST method.

Here is another answer: You might try sending your response back as a ResponseEntity instead of using the HttpServletResponse directly. My hunch is that second argument, the HttpServletRequest argument, is what is causing the problem. I've never used that. I've always send my response back using the spring mvc api.
Comment for this answer: Thank you for the response, the problem is it never arrives to the response phase. I mean it generates error when it tries to receive the json as input. My response is a CVS file and I think the current code should be fine because it works perfectly with GET method.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 11, 'CommentCount': 12, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2015:00:12/23/15', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<java><jquery><json><ajax><restful-architecture>', 'Title': 'Simple restful JSON POST with java as server and jquery as client', 'ViewCount': 2217, 'id': 34445053, 'user_AboutMe': '<p>Technology Enthusiast</p>\n<p>B.Sc in Computer Science,<br />\nM.Sc in Computer Science (Human-Computer-Interactions)</p>\n', 'user_AccountId': 4048506.0, 'user_DisplayName': 'Arashsoft', 'user_Reputation': 2589.0, 'user_Views': 573.0, 'user_id': 3328979.0}}