Reputation: 2445
I found multiple solutions for this exception and causes but none worked and it seems illogical.
I have REST service class as the following
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.MediaType;
import java.util.Map;
@RestController
public class UserRestService {
@RequestMapping(value = "/userLogin", method = RequestMethod.POST, produces = MediaType.APPLICATION_XML_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public @ResponseBody ResponseEntity<Map> login(@RequestBody Map<String, String> name) {
ResponseEntity<Map> res = null;
name.values().forEach(System.out::println);
return new ResponseEntity<Map>(name, HttpStatus.OK);
}
}
As you see, I try to create a POST request with request body as JSON and response as XML, printing the request in the process. It's just simple example but while the request is printed correctly which means it's been received and marshaled to Map. However the response status is 406 (not acceptable)
Exception in the log is
John
30
null
2018-08-16 14:05:48.440 WARN 22820 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
2018-08-16 14:05:48.481 WARN 22820 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
the Request Header simply has
Accept:*/*
Content-Type:application/json
POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.cms</groupId>
<artifactId>business</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Noting that adding the following dependency solves the problem
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Request Body { "name":"John", "age":30, "car":null }
Response if MediaType.APPLICATION_JSON_UTF8_VALUE
is used for produces
attribute of @RequestMapping
is { "name":"John", "age":30, "car":null }
Response if MediaType.APPLICATION_XML_VALUE
is used for produces
attribute of @RequestMapping
& jackson-dataformat-xml
used is
<Map>
<name>John</name>
<age>30</age>
<car/>
</Map>
Why using JAXB fails in this ?
OK as @Simon comment, I created a sample object (class) to get as request and response with it. Same exact effect. Here is the updated code
public class MockupResponse {
private String name;
private Integer age;
private String car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
if (null != name)
sb.append("Name: " + name + "\n");
if (null != age)
sb.append("Age: " + age + "\n");
if (null != car)
sb.append("Car: " + car + "\n");
return sb.toString();
}
}
Service
@RequestMapping(value = "/userLogin", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public @ResponseBody ResponseEntity<MockupResponse> login(@RequestBody MockupResponse sample) {
System.out.println(sample);
return new ResponseEntity<MockupResponse>(sample, HttpStatus.OK);
}
Upvotes: 3
Views: 13472
Reputation: 36223
Add @XmlRootElement to the class that must be serialized by JAXB like
@XmlRootElement
public class MockupResponse {
private String name;
private Integer age;
private String car;
...
}
Then the XML serialization works.
Read more about that in the Spring Doc:
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html
If you use Java 9 and later you must add JAXB and javax.activation to the dependencies:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
Upvotes: 5