Springboot中的HttpMessageNotWritableException异常:没有与预设Content-Type 'null'相对应的转换器[...]。

11

我尝试使用Springboot 2.2.4.RELEASE + JDK11和java 8编译来创建支持XML和JSON的Web API。

我的模型:

@XmlRootElement
public class DataModel {

    private List<String> columns;

    private List<Row> rows;

    public List<String> getColumns() {
        return columns;
    }

    public void setColumns(List<String> columns) {
        this.columns = columns;
    }

    public List<Row> getRows() {
        return rows;
    }

    public void setRows(List<Row> rows) {
        this.rows = rows;
    }

}

我的控制器:

@RequestMapping(value = "/{model}/columns", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<DataModel> getColumnsModel(@PathVariable String model) {
    LOGGER.info("getColumnsModel : model[{}]", model);
    DataModel dataModel = modelService.getColumns(model);
    return Optional.ofNullable(dataModel).map(result -> new ResponseEntity<>(result, HttpStatus.OK)).orElse(new ResponseEntity<>(HttpStatus.NO_CONTENT));
}

我使用curl:

curl -s -v --header "Accept: application/xml" http://localhost:8084/api/foo/columns

在我的电脑上(Windows 10),结果是正常的。

* TCP_NODELAY set
* Connected to localhost (::1) port 8084 (#0)
> GET /noraui/api/hello/columns HTTP/1.1
> Host: localhost:8084
> User-Agent: curl/7.67.0
> Accept: application/xml
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Tue, 03 Mar 2020 08:38:20 GMT
<
{ [254 bytes data]
* Connection #0 to host localhost left intact

我的错误(在travis-ci上的Unix平台):

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.github.noraui.data.rest.DataModel] with preset Content-Type 'null']

< HTTP/1.1 500 
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Length: 0
< Date: Tue, 03 Mar 2020 08:41:28 GMT
< Connection: close
< 
* Closing connection 0
8个回答

4
我已经通过添加以下依赖项解决了这个问题:
<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
  <version>2.12.3</version>
</dependency>

3
我曾遇到过类似的错误,但是与JSON有关。我的问题是由于我尝试将POJO转换为JSON时,其中有两个具有相同名称的属性。
@JsonProperty("my_property")
[...]
@JsonProperty("my_property")  // duplicated property name in the same POJO.

修复了重复问题后,对象可以正确转换。

这是一个很好的示例,展示了如何使用JsonProperty:https://stackoverflow.com/questions/12583638/when-is-the-jsonproperty-property-used-and-what-is-it-used-for - undefined

1

在我的案例中,我正在处理一个已经存在的API,该API生成PDF并需要将响应更改为JSON。我忘记从@GetMapping注释中删除produces =“application/pdf”


0
在我的特殊情况下,我在尝试运行Spring Boot控制器类的集成测试时遇到了这个错误。我怀疑可能是由于模拟的Spring上下文导致运行时库/类加载出现问题,但我无法理解确切缺少什么... 我仍然不能理解,希望有人能更详细地解释这个问题。我尝试自己转换为JSON并返回一个字符串,在ResponseEntity的正文中,这起作用了,因为我必须将Jackson的ObjectMapper指定为SpringBootTest(classes = {...})中的一个类。所以这个方法可行:
ResponseMessage m = new ResponseMessage("haha");
ResponseEntity r = ResponseEntity.status(HttpStatus.OK).body(objectMapper.writeValueAsString(m));

但这一开始并没有发生(这是我的问题):

ResponseMessage m = new ResponseMessage("haha");
ResponseEntity r = ResponseEntity.status(HttpStatus.OK).body(m); // exception happens further while being processed by Spring

异常:

mo.s.w.s.m.s.DefaultHandlerExceptionResolver.logException - Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class gr.unisystems.ethemisid.view.model.response.ResponseMessage] with preset Content-Type 'null'] 
mo.s.t.w.s.TestDispatcherServlet.logResult - Completed 500 INTERNAL_SERVER_ERROR

嗨@hello_earth,我目前也遇到了同样的问题。你找到解决方案了吗? - The Reedemed77
@TheReedemed77 我很不舒服地说,但我的答案是否定的。也许在ResponseEntity上设置内容类型(除了状态和正文之外),会有所帮助?既然找到了解决方法,我就转而处理其他事情了。 - hello_earth
1
谢谢。我最终找到了解决方案。我在我的测试中遇到了问题。我正在使用Spock框架。我所做的唯一更改是使用WebMvcTest(SomeClassName)而不是SpringBootTest(SomeClassName)。我还使用SpringBean来注入此类中其他依赖项的模拟。 - The Reedemed77

0

你能用Postman进行一次测试吗?我刚刚使用Postman进行了测试,结果很好。但是,请仔细检查你的请求头两次,并确保它是正确的。

P.S.:我在github.com/NoraUi/noraui-datas-webservices上检查了项目,并使用了提到的依赖项(jaxb-runtime和xerces)进行了测试,发现这些依赖项根本不必要。@XmlRootElement注释应该足够了。我刚刚向我的GitHub账户提交了一个个人项目。它是一个更简洁的示例。请看这里:https://github.com/DavidGuimaraes/spring-security-basic


0

有时候,当您尝试返回实体而不是实体的DTO时,可能会出现此错误。您可能已经创建了该DTO作为实际实体的XMLRootElement,从您的RestController方法中返回。

要么不返回任何内容(void),要么从RestController的方法中返回正确注释的类的实例。

我理解OP的这个异常是由于他在pom文件中缺少适当的依赖关系引起的。尽管如此,上述提到的技巧是您可以解决此问题的方法之一。或者,也许只有我才有这种粗心的问题。 :'D

您的最终方法代码可能看起来像这样:

    @ResponseBody
    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping(value = "/xml",
            consumes = MediaType.APPLICATION_XML_VALUE,
            produces = MediaType.APPLICATION_XML_VALUE)
    public void addPaymentXml(@RequestBody String paymentXml)
            throws IOException, SAXException {
        paymentService.createPaymentXml(paymentXml);
    }

0
在模型类中添加'toString()'方法对我很有用。(我使用了@Data Lombok注释来实现这一点)

-1
有时候问题与你想要作为 JSON 返回的对象有关。也许你缺少构造函数或一些方法,比如 getters 等等。在返回的类上使用 Lombok 的 @Data 注解很可能会解决这个问题。

我不使用 Lombok。 - Stéphane GRILLON
然后请添加空的和完整的构造函数,以及所有的getter和setter。还要在类中添加toString()和equals()方法。这样你就安全了。 - m.semnani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接