已配置的ObjectMapper未用于spring-boot-webflux

00jrzges  于 2023-08-04  发布在  Spring
关注(0)|答案(6)|浏览(180)

我在我的objectmapperbuilder配置中配置了mixin,使用常规的spring web控制器,根据mixin输出数据。然而,使用webflux,一个带有返回Flow或Mono方法的控制器会将数据序列化,就像objectmapper是默认的一样。
如何让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);
}

字符串

j2cgzkjk

j2cgzkjk1#

实际上,我通过单步执行init代码找到了解决方案:

@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);
            }
        };

    }
}

字符串

iyfamqjs

iyfamqjs2#

为了方便起见,我将@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)
        );
    }
}

字符串

gmol1639

gmol16393#

只需实现WebFluxConfigurer,覆盖方法configureHttpMessageCodecs
Sping 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)))
    }
}

字符串
确保要编码/解码的所有数据类的所有属性都使用**@JsonProperty**注解,即使class和json数据中的属性名称相同

data class MyClass(
    @NotNull
    @JsonProperty("id")
    val id: String,

    @NotNull
    @JsonProperty("my_name")
    val name: String)

uttx8gqw

uttx8gqw4#

在我的例子中,我尝试使用自定义的ObjectMapper,同时继承应用默认WebClient的所有行为。
我发现我必须使用WebClient.Builder.codecs。当我使用WebClient.Builder.exchangeStrategies时,提供的覆盖被忽略。不确定这种行为是否是特定于使用WebClient.mutate的,但这是我发现的唯一有效的解决方案。

WebClient customizedWebClient = webClient.mutate()
                                         .codecs(clientCodecConfigurer -> 
                                                     clientCodecConfigurer.defaultCodecs()
                                                                          .jackson2JsonDecoder(new Jackson2JsonDecoder(customObjectMapper)))
                                         .build();

字符串

d4so4syb

d4so4syb5#

我已经尝试了所有不同的解决方案(@Primary @Bean用于ObjectMapperconfigureHttpMessageCodecs()等)。最后对我起作用的是指定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)
    }
}

字符串

ct3nt3jp

ct3nt3jp6#

正如我在回答here中所解释的,你可以省略臃肿的编解码器配置,只像这样定义bean:

@Bean
public WebClient webClient(WebClient.Builder builder) {
    return builder.build();
}

字符串
主要问题是Sping Boot 会自动配置WebClientbuilder,而不是实际的示例。手动创建的WebClient示例使用其内置的默认Map器,因此您必须手动配置编解码器。

相关问题