[英]ObjectMapper in spring boot can read string, but doesn't work when parsing headers
I am trying to give an enum value as a header parameter to my rest endpoint in a spring boot @RestController
.我试图在 spring 引导
@RestController
枚举值作为 header 参数提供给我的 rest 端点。 To that end I put the jackson libraries in my build.gradle
file since the autogenerated enum used jackson annotations.为此,我将 jackson 库放在我的
build.gradle
文件中,因为自动生成的枚举使用了 jackson 注释。 I cannot change the enum code (it is autogenerated from a openapi specification).我无法更改枚举代码(它是从 openapi 规范自动生成的)。 It looks like this:
它看起来像这样:
public enum DocumentTypes {
APPLICATION_PDF("application/pdf"),
APPLICATION_RTF("application/rtf"),
APPLICATION_VND_OASIS_OPENDOCUMENT_TEXT("application/vnd.oasis.opendocument.text"),
APPLICATION_VND_OPENXMLFORMATS_OFFICEDOCUMENT_WORDPROCESSINGML_DOCUMENT("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
APPLICATION_VND_MS_WORD("application/vnd.ms-word"),
TEXT_HTML("text/html"),
TEXT_PLAIN("text/plain");
private String value;
DocumentTypes(String value) {
this.value = value;
}
@Override
@JsonValue
public String toString() {
return String.valueOf(value);
}
@JsonCreator
public static DocumentTypes fromValue(String text) {
for (DocumentTypes b : DocumentTypes.values()) {
if (String.valueOf(b.value).equals(text)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + text + "'");
}
}
The restcontroller I am using to test looks like this:我用来测试的 restcontroller 看起来像这样:
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(path = "", method = RequestMethod.GET)
public void test(@RequestHeader(value = "Accept", required = false) DocumentTypes targetFormat) throws IOException {
DocumentTypes value = objectMapper.readValue("\"application/pdf\"", DocumentTypes.class);
}
}
If I don't supply the Accept header and just let break inside the code I can see that the first line of the code works fine, the application/pdf
String is transformed into value
so the ObjectMapper
did its job using the @JsonCreator
method.如果我不提供 Accept header 并让 break 在代码中,我可以看到代码的第一行工作正常,
application/pdf
字符串被转换为value
,因此ObjectMapper
使用@JsonCreator
方法完成了它的工作。
However if I pass Accept=application/pdf
header along with the request I get an error:但是,如果我通过
Accept=application/pdf
header 以及请求,我会收到错误消息:
Failed to convert value of type 'java.lang.String' to required type 'de.some.namespace.model.DocumentTypes';
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestHeader de.some.namespace.model.DocumentTypes] for value 'application/pdf';
nested exception is java.lang.IllegalArgumentException: No enum constant de.some.namespace.model.DocumentTypes.application/pdf"
This looks to me as if spring is not using the Jackson provided ObjectMapper
, thus ignoring the @JsonCreator
method and just trying to resolve the enum by default by looking if there is a key with that provided name.这在我看来好像 spring 没有使用 Jackson 提供的
ObjectMapper
,因此忽略了@JsonCreator
方法,只是尝试通过查看是否存在具有提供的名称的键来默认解析枚举。
This to me does not make sense, becuase I also only @Autowire
the ObjectMapper
,... isn't that the one that spring should also use, how can I force spring to use the correct one for parsing the arguments?这对我来说没有意义,因为我也只有
@Autowire
ObjectMapper
,...不是 spring 也应该使用的那个,我怎样才能强制 spring 使用正确的解析 ZDBC11CAADABD8BDA9E I tried putting it into a @Configuration
and making it a @Bean
and @Primary
with the same results.我尝试将其放入
@Configuration
并使其成为具有相同结果的@Bean
和@Primary
。
I have a workaround by implementing a converter:我有一个通过实现转换器的解决方法:
@Component
public class StringToDocumentTypesConverter implements Converter<String, DocumentTypes> {
@Autowired
private ObjectMapper mapper;
@Override
public DocumentTypes convert(String s) {
try {
return mapper.readValue(String.format("\"%s\"", s), DocumentTypes.class);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
But I don't understand why this would be necessary, normally spring automatically puts arguments through the ObjectMapper
.但我不明白为什么这是必要的,通常 spring 会自动通过
ObjectMapper
放置 arguments 。
I think this is working as designed.我认为这是按设计工作的。 Spring only uses the Jackson
ObjectMapper
for conversion of message bodies (using a registered HttpMessageConverter
, specifically the MappingJackson2HttpMessageConverter
). Spring 仅使用 Jackson
ObjectMapper
来转换消息体(使用已注册的HttpMessageConverter
,特别是MappingJackson2HttpMessageConverter
)。
This is documented at https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-typeconversion :这记录在https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-typeconversion :
Some annotated controller method arguments that represent String-based request input (such as
@RequestParam
,@RequestHeader
,@PathVariable
,@MatrixVariable
, and@CookieValue
) can require type conversion if the argument is declared as something other than String.如果参数声明为 String 以外的其他内容,则表示基于字符串的请求输入(例如
@PathVariable
@MatrixVariable
@RequestParam
@RequestHeader
@CookieValue
的一些带注释的 controller 方法 arguments 可能需要类型转换。For such cases, type conversion is automatically applied based on the configured converters
对于这种情况,类型转换会根据配置的转换器自动应用
And https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestbody :和https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestbody :
You can use the
@RequestBody
annotation to have the request body read and deserialized into an Object through anHttpMessageConverter
您可以使用
@RequestBody
注释通过 HttpMessageConverter 读取请求正文并将其反序列化为HttpMessageConverter
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.