spring-boot-webflux 中未使用已配置的 ObjectMapper
Configured ObjectMapper not used in spring-boot-webflux
我在我的 objectmapperbuilder 配置中配置了 mixins,使用常规 spring 网络控制器,根据 mixins 输出数据。
但是,使用 webflux,具有返回 Flow 或 Mono 方法的控制器会将数据序列化,就像对象映射器是默认对象一样。
如何让 webflux 强制使用 objectmapper 配置?
示例配置:
@Bean
JavaTimeModule javatimeModule(){
return new JavaTimeModule();
}
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.mixIn(MyClass.class, MyClassMixin.class);
}
我实际上通过逐步执行初始化代码找到了我的解决方案:
@Configuration
public class Config {
@Bean
JavaTimeModule javatimeModule(){
return new JavaTimeModule();
}
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.mixIn(MyClass.class, MyClassMixin.class);
}
@Bean
Jackson2JsonEncoder jackson2JsonEncoder(ObjectMapper mapper){
return new Jackson2JsonEncoder(mapper);
}
@Bean
Jackson2JsonDecoder jackson2JsonDecoder(ObjectMapper mapper){
return new Jackson2JsonDecoder(mapper);
}
@Bean
WebFluxConfigurer webFluxConfigurer(Jackson2JsonEncoder encoder, Jackson2JsonDecoder decoder){
return new WebFluxConfigurer() {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(encoder);
configurer.defaultCodecs().jackson2JsonDecoder(decoder);
}
};
}
}
只需实施 WebFluxConfigurer 并覆盖方法 configureHttpMessageCodecs
Spring Boot 2 + Kotlin
的示例代码
@Configuration
@EnableWebFlux
class WebConfiguration : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().jackson2JsonEncoder(Jackson2JsonEncoder(ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)))
configurer.defaultCodecs().jackson2JsonDecoder(Jackson2JsonDecoder(ObjectMapper()
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)))
}
}
确保您的所有数据 class 都 encoded/decoded 的所有属性都带有 @JsonProperty 注释,即使 属性 名称是在 class 和 json 数据
中相等
data class MyClass(
@NotNull
@JsonProperty("id")
val id: String,
@NotNull
@JsonProperty("my_name")
val name: String)
我将@Alberto Galiana 的解决方案翻译成 Java 并为方便起见注入了已配置的 Objectmapper,因此您无需进行多次配置:
@Configuration
@RequiredArgsConstructor
public class WebFluxConfig implements WebFluxConfigurer {
private final ObjectMapper objectMapper;
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(
new Jackson2JsonEncoder(objectMapper)
);
configurer.defaultCodecs().jackson2JsonDecoder(
new Jackson2JsonDecoder(objectMapper)
);
}
}
我已经尝试了所有不同的解决方案(@Primary @Bean
for ObjectMapper
、configureHttpMessageCodecs()
等)。最后对我有用的是指定 MIME 类型。这是一个例子:
@Configuration
class WebConfig: WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
val encoder = Jackson2JsonEncoder(objectMapper, MimeTypeUtils.APPLICATION_JSON)
val decoder = Jackson2JsonDecoder(objectMapper, MimeTypeUtils.APPLICATION_JSON)
configurer.defaultCodecs().jackson2JsonEncoder(encoder)
configurer.defaultCodecs().jackson2JsonDecoder(decoder)
}
}
在我的例子中,我尝试使用自定义 ObjectMapper
,同时从我的应用程序的默认 WebClient
.
继承所有行为
我发现我不得不使用 WebClient.Builder.codecs
。当我使用 WebClient.Builder.exchangeStrategies
时,提供的覆盖被忽略了。不确定这种行为是否特定于使用 WebClient.mutate
,但这是我发现唯一有效的解决方案。
WebClient customizedWebClient = webClient.mutate()
.codecs(clientCodecConfigurer ->
clientCodecConfigurer.defaultCodecs()
.jackson2JsonDecoder(new Jackson2JsonDecoder(customObjectMapper)))
.build();
我在我的 objectmapperbuilder 配置中配置了 mixins,使用常规 spring 网络控制器,根据 mixins 输出数据。 但是,使用 webflux,具有返回 Flow 或 Mono 方法的控制器会将数据序列化,就像对象映射器是默认对象一样。
如何让 webflux 强制使用 objectmapper 配置?
示例配置:
@Bean
JavaTimeModule javatimeModule(){
return new JavaTimeModule();
}
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.mixIn(MyClass.class, MyClassMixin.class);
}
我实际上通过逐步执行初始化代码找到了我的解决方案:
@Configuration
public class Config {
@Bean
JavaTimeModule javatimeModule(){
return new JavaTimeModule();
}
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.mixIn(MyClass.class, MyClassMixin.class);
}
@Bean
Jackson2JsonEncoder jackson2JsonEncoder(ObjectMapper mapper){
return new Jackson2JsonEncoder(mapper);
}
@Bean
Jackson2JsonDecoder jackson2JsonDecoder(ObjectMapper mapper){
return new Jackson2JsonDecoder(mapper);
}
@Bean
WebFluxConfigurer webFluxConfigurer(Jackson2JsonEncoder encoder, Jackson2JsonDecoder decoder){
return new WebFluxConfigurer() {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(encoder);
configurer.defaultCodecs().jackson2JsonDecoder(decoder);
}
};
}
}
只需实施 WebFluxConfigurer 并覆盖方法 configureHttpMessageCodecs
Spring Boot 2 + Kotlin
的示例代码@Configuration
@EnableWebFlux
class WebConfiguration : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().jackson2JsonEncoder(Jackson2JsonEncoder(ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)))
configurer.defaultCodecs().jackson2JsonDecoder(Jackson2JsonDecoder(ObjectMapper()
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)))
}
}
确保您的所有数据 class 都 encoded/decoded 的所有属性都带有 @JsonProperty 注释,即使 属性 名称是在 class 和 json 数据
中相等data class MyClass(
@NotNull
@JsonProperty("id")
val id: String,
@NotNull
@JsonProperty("my_name")
val name: String)
我将@Alberto Galiana 的解决方案翻译成 Java 并为方便起见注入了已配置的 Objectmapper,因此您无需进行多次配置:
@Configuration
@RequiredArgsConstructor
public class WebFluxConfig implements WebFluxConfigurer {
private final ObjectMapper objectMapper;
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(
new Jackson2JsonEncoder(objectMapper)
);
configurer.defaultCodecs().jackson2JsonDecoder(
new Jackson2JsonDecoder(objectMapper)
);
}
}
我已经尝试了所有不同的解决方案(@Primary @Bean
for ObjectMapper
、configureHttpMessageCodecs()
等)。最后对我有用的是指定 MIME 类型。这是一个例子:
@Configuration
class WebConfig: WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
val encoder = Jackson2JsonEncoder(objectMapper, MimeTypeUtils.APPLICATION_JSON)
val decoder = Jackson2JsonDecoder(objectMapper, MimeTypeUtils.APPLICATION_JSON)
configurer.defaultCodecs().jackson2JsonEncoder(encoder)
configurer.defaultCodecs().jackson2JsonDecoder(decoder)
}
}
在我的例子中,我尝试使用自定义 ObjectMapper
,同时从我的应用程序的默认 WebClient
.
我发现我不得不使用 WebClient.Builder.codecs
。当我使用 WebClient.Builder.exchangeStrategies
时,提供的覆盖被忽略了。不确定这种行为是否特定于使用 WebClient.mutate
,但这是我发现唯一有效的解决方案。
WebClient customizedWebClient = webClient.mutate()
.codecs(clientCodecConfigurer ->
clientCodecConfigurer.defaultCodecs()
.jackson2JsonDecoder(new Jackson2JsonDecoder(customObjectMapper)))
.build();