Spring Boot REST 端点忽略 Content-Type
Posted
技术标签:
【中文标题】Spring Boot REST 端点忽略 Content-Type【英文标题】:Spring Boot REST endpoint ignores Content-Type 【发布时间】:2020-10-27 21:34:07 【问题描述】:我在创建具有 application/xml 类型的简单 REST 控制器时遇到问题。 我正在使用 Kotlin 并通过在 Gradle KTS 中提供依赖项来注册 Jackson 转换器
“实施”(组=“com.fasterxml.jackson.dataformat”,名称=“jackson-dataformat-xml”,版本=jacksonXmlVersion)
Controller 使用 Swagger,看起来像这样:
@ApiOperation(
value = "Epcis capture point",
response = EPCISDocResponse::class,
httpMethod = "POST"
)
@PostMapping(
"/capture",
consumes = [MediaType.APPLICATION_XML_VALUE],
produces = [MediaType.APPLICATION_XML_VALUE]
)
fun capture(@RequestBody request: EPCISDocumentType): ResponseEntity<EPCISDocResponse>
doSomething()
我的模型类是由 XJC 生成的,看起来像这样:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EPCISDocumentType", propOrder =
"epcisHeader",
"epcisBody",
"extension",
"any"
)
@XmlRootElement(name = "EPCISDocument", namespace = "urn:epcglobal:epcis:xsd:1")
public class EPCISDocumentType
extends Document
问题是 Spring Boot 找不到 application/xml 对应的转换器,并尝试将其解析为 JSON,给我下一个错误:
.w.s.m.s.DefaultHandlerExceptionResolver:已解决 [org.springframework.http.converter.HttpMessageNotReadableException:JSON 解析错误:无法反序列化
java.util.ArrayList<java.lang.Object>
的实例,超出 VALUE_STRING 令牌;嵌套异常是 com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance ofjava.util.ArrayList<java.lang.Object>
out of VALUE_STRING token 在 [来源:(PushbackInputStream);行:4,列:2](通过引用链:epcis.capture.EPCISDocumentType["any"])]
我为 SOAPTemplate 定义了一个 Jaxb2 编组器,它可能会干扰:
@Bean
fun marshaller(): Jaxb2Marshaller?
val marshaller = Jaxb2Marshaller()
marshaller.setClassesToBeBound(
epcis.capture.EPCISDocumentType::class.java,
CaptureEPCISDocResponse::class.java,
LeanEPCISDocResponse::class.java
)
return marshaller
非常感谢任何帮助,这是我第一次看到杰克逊映射到内容类型的问题。
在应用程序上下文中注册的转换器列表:
org.springframework.http.converter.StringHttpMessageConverter@531bfe4b
org.springframework.http.converter.ResourceHttpMessageConverter@2c8f7d6a
org.springframework.http.converter.ResourceRegionHttpMessageConverter@77331437
org.springframework.http.converter.xml.SourceHttpMessageConverter@98a0842
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@56f569e
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter@525c0f74
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@3da12ba4
更新
我能够通过删除 MappingJackson2XmlHttpMessageConverter 来解决这个问题,因为我的模型包含 XmlRootElement 并且应该由 Jaxb2RootElementHttpMessageConverter 编组,但现在问题更加奇怪了。 现在,Jaxb2Root 转换器没有将它编组到我的对象中,而是为我的控制器提供了 JAXBElement:
Method [public org.springframework.http.ResponseEntity<com.movilizer.lean.model.epcis.LeanEPCISDocResponse> com.movilizer.lean.leanepcis.controller.EpcisController.capture(epcis.capture.EPCISDocumentType)] with argument values:
[0] [type=javax.xml.bind.JAXBElement] [value=javax.xml.bind.JAXBElement@76e6ecc4] ] with root cause
根据我的发现,似乎是特定的 sun jaxb-impl 负责此问题,因此解析器提供 JAXBElement 而不是有效负载本身。 有什么帮助吗?
【问题讨论】:
【参考方案1】:我放弃了让 Jaxb2RootElementHttpMessageConverter 正常工作的想法,所以我只是将我的 rest 控制器更改为接受 String 值:
private val unmarshaller = javax.xml.bind.JAXBContext.newInstance(EPCISDocumentType::class.java).createUnmarshaller()
@PostMapping(
"/capture",
consumes = [MediaType.APPLICATION_XML_VALUE],
produces = [MediaType.APPLICATION_XML_VALUE]
)
fun capture(@RequestBody payload: String): ResponseEntity<String>
val request = (unmarshaller.unmarshal(StringReader(payload)) as JAXBElement<EPCISDocumentType>).value
遗憾的是,我对应该开箱即用的调试工具不感兴趣,但不感兴趣。 我想要一个“有效”的解决方案,但不实现自定义转换器,但看起来 JAXB 特定的实现和 Spring 集成有问题。
【讨论】:
以上是关于Spring Boot REST 端点忽略 Content-Type的主要内容,如果未能解决你的问题,请参考以下文章
没有 REST 端点在 Spring Boot 应用程序中工作
为啥 spring-boot-starter-jdbc 会破坏我的 REST 端点?
Spring-Boot REST 服务基本 http 身份验证排除一个端点