POST JSON fails with 415 Unsupported media type, Spring 3 mvc

AjaxJsonSpringPostHttp Status-Code-415

Ajax Problem Overview


I am trying to send a POST request to a servlet. Request is sent via jQuery in this way:

var productCategory = new Object();
productCategory.idProductCategory = 1;
productCategory.description = "Descrizione2";
newCategory(productCategory);

where newCategory is

function newCategory(productCategory)
{
  $.postJSON("ajax/newproductcategory", productCategory, function(
      idProductCategory)
  {
    console.debug("Inserted: " + idProductCategory);
  });
}

and postJSON is

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

With firebug I see that JSON is sent correctly:

{"idProductCategory":1,"description":"Descrizione2"}

But I get 415 Unsupported media type. Spring mvc controller has signature

	@RequestMapping(value = "/ajax/newproductcategory", method = RequestMethod.POST)
public @ResponseBody
Integer newProductCategory(HttpServletRequest request,
		@RequestBody ProductCategory productCategory)

Some days ago it worked, now it is not. I'll show more code if needed.

Ajax Solutions


Solution 1 - Ajax

I've had this happen before with Spring @ResponseBody and it was because there was no accept header sent with the request. Accept header can be a pain to set with jQuery, but this worked for me source

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    headers: { 
        'Accept': 'application/json',
        'Content-Type': 'application/json' 
    },
    'type': 'POST',
    'url': url,
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

The Content-Type header is used by @RequestBody to determine what format the data being sent from the client in the request is. The accept header is used by @ResponseBody to determine what format to sent the data back to the client in the response. That's why you need both headers.

Solution 2 - Ajax

adding content type into the request as application/json resolved the issue

Solution 3 - Ajax

I had a similar problem but found the issue was that I had neglected to provide a default constructor for the DTO that was annotated with @RequestBody.

Solution 4 - Ajax

I faced a similar issue and this is how I fixed it,

The problem is due to the conversion process from JSON to Java, one need to have the right run time jackson libraries for the conversion to happen correctly.

Add the following jars (through dependency or by downloading and adding to the classpath.

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>

This should fix the problem.

Complete Code:

function() {
  $.ajax({
    type: "POST",
    url: "saveUserDetails.do",
    data: JSON.stringify({
      name: "Gerry",
      ity: "Sydney"
    }),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    success: function(data) {
      if (data.status == 'OK')
        alert('Person has been added');
      else
        alert('Failed adding person: ' + data.status + ', ' + data.errorMessage);
}
 					
					

and the controller signature looks like this:

@RequestMapping(value = "/saveUserDetails.do", method = RequestMethod.POST)
public @ResponseBody Person addPerson( @RequestBody final  Person person) {

Hope this helps

Solution 5 - Ajax

I believe I ran exactly into the same issue. After countless hours of fighting with the JSON, the JavaScript and the Server, I found the culprit: In my case I had a Date object in the DTO, this Date object was converted to a String so we could show it in the view with the format: HH:mm.

When JSON information was being sent back, this Date String object had to be converted back into a full Date Object, therefore we also need a method to set it in the DTO. The big BUT is you cannot have 2 methods with the same name (Overload) in the DTO even if they have different type of parameter (String vs Date) because this will give you also the 415 Unsupported Media type error.

This was my controller method

  @RequestMapping(value = "/alarmdownload/update", produces = "application/json", method = RequestMethod.POST)
  public @ResponseBody
  StatusResponse update(@RequestBody AlarmDownloadDTO[] rowList) {
    System.out.println("hola");
    return new StatusResponse();
  }

This was my DTO example (id get/set and preAlarm get Methods are not included for code shortness):

@JsonIgnoreProperties(ignoreUnknown = true)
public class AlarmDownloadDTO implements Serializable {
  
  private static final SimpleDateFormat formatHHmm = new SimpleDateFormat("HH:mm");

  private String id;
  private Date preAlarm;
  
  public void setPreAlarm(Date date) { 
    this.preAlarm == date;
  }
  public void setPreAlarm(String date) {    
    try {
      this.preAlarm = formatHHmm.parse(date);
    } catch (ParseException e) {
      this.preAlarm = null;
    } catch (NullPointerException e){
      this.preAlarm = null;
    }
  }
}

To make everything work you need to remove the method with Date type parameter. This error is very frustrating. Hope this can save someone hours of debugging.

Solution 6 - Ajax

I faced this issue when I integrated spring boot with spring mvc. I solved it by just adding these dependencies.

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>

Solution 7 - Ajax

A small side note - stumbled upon this same error while developing a web application. The mistake we found, by toying with the service with Firefox Poster, was that both fields and values in the Json should be surrounded by double quotes. For instance..

[ {"idProductCategory" : "1" , "description":"Descrizione1"},   {"idProductCategory" : "2" , "description":"Descrizione2"} ]

In our case we filled the json via javascript, which can be a little confusing when it comes with dealing with single/double quotes, from what I've heard.

What's been said before in this and other posts, like including the 'Accept' and 'Content-Type' headers, applies too.

Hope t'helps.

Solution 8 - Ajax

I managed out how to make it works. Tell me in case I am wrong. I used only one way to serialize/deserialize: I removed all annotations regarding this (@JSONSerialize and @JSONDeserialize) and registered Serializers and Deserializers in CustomObjectMapper class. I didn't find an article explaining this behaviour but I resolved in this way. Hope it's useful.

Solution 9 - Ajax

I had the same problem. I had to follow these steps to resolve the issue:

1. Make sure you have the following dependencies:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>

2. Create the following filter:

    public class CORSFilter extends OncePerRequestFilter {
    
        @Override
        protected void doFilterInternal(HttpServletRequest request,
                                        HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
    
            String origin = request.getHeader("origin");
            origin = (origin == null || origin.equals("")) ? "null" : origin;
            response.addHeader("Access-Control-Allow-Origin", origin);
            response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, DELETE, OPTIONS");
            response.addHeader("Access-Control-Allow-Credentials", "true");
            response.addHeader("Access-Control-Allow-Headers",
                    "Authorization, origin, content-type, accept, x-requested-with");
    
            filterChain.doFilter(request, response);
        }
    }

3. Apply the above filter for the requests in web.xml

    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.your.package.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

I hope this is useful to somebody.

Solution 10 - Ajax

Spring boot + spring mvn

with issue

@PostMapping("/addDonation")
public String addDonation(@RequestBody DonatorDTO donatorDTO) {

with solution

@RequestMapping(value = "/addDonation", method = RequestMethod.POST)
@ResponseBody
public GenericResponse addDonation(final DonatorDTO donatorDTO, final HttpServletRequest request){

Solution 11 - Ajax

I resolved this issue by adding jackson-json data binding to my pom.

<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.6.3</version>
</dependency>

Solution 12 - Ajax

In your Model Class add a json property annotation, also have a default constructor

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

Solution 13 - Ajax

I had the same issue. adding

<mvc:annotation-driven />
<mvc:default-servlet-handler />

to the spring-xml solved it

Solution 14 - Ajax

In addition to setting the Accept and Content-Type headers, and making sure they match the consumes/produces settings for your controller method, you may also want to look at the JSON structure and making sure there are no issues with marshalling and unmarshalling. In my case the content type was OK, but there were issues with mapping JSON requests to my request/response model. Normally the controller should return a 400 error rather than a 415 error, but in my case the error code was 415. I debugged the issue by adding a test class where I used an ObjectMapper to read my JSON into the request model object. The ObjectMapper choked on the request, and gave me helpful errors that helped me fix my model class definition.

Solution 15 - Ajax

1.a. Add following in applicationContext-mvc.xml

xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc

  1. add jackson library

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiongc5View Question on Stackoverflow
Solution 1 - AjaxtheonView Answer on Stackoverflow
Solution 2 - AjaxuiroshanView Answer on Stackoverflow
Solution 3 - AjaxJohn ShepherdView Answer on Stackoverflow
Solution 4 - AjaxvinSanView Answer on Stackoverflow
Solution 5 - Ajaxwill824View Answer on Stackoverflow
Solution 6 - AjaxdeepView Answer on Stackoverflow
Solution 7 - AjaxCarlos RomeroView Answer on Stackoverflow
Solution 8 - Ajaxgc5View Answer on Stackoverflow
Solution 9 - AjaxManoj ShresthaView Answer on Stackoverflow
Solution 10 - AjaxShahid Hussain AbbasiView Answer on Stackoverflow
Solution 11 - AjaxLingasamy BagavathiView Answer on Stackoverflow
Solution 12 - AjaxdekoView Answer on Stackoverflow
Solution 13 - AjaxOhadRView Answer on Stackoverflow
Solution 14 - AjaxMorten JorgensenView Answer on Stackoverflow
Solution 15 - AjaxVictorView Answer on Stackoverflow