I have a @JsonComponent that extends JsonSerializer:
@JsonComponent
public class SomeObjectSerializer extends JsonSerializer<SomeObject> {
@Override
public void serialize(SomeObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeStartObject();
gen.writeObjectField("a", value.getA());
gen.writeEndObject();
}
}
for this object:
public class SomeObject {
public final String a;
public final String b;
public SomeObject(String a, String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}
Using Spring Web MVC it gets picked up automatically in Spring Boot, so that a controller returning SomeObject as JSON renders {"a":"aa"}.
However when used with WebFlux, I see SomeObjectSerializer initialized but never used, the following controller
@RestController
public class SomeController {
@GetMapping("/someObject")
public Mono<SomeObject> getSomeObject() {
return Mono.just(new SomeObject("aa", "bb"));
}
}
always renders {"a":"aa","b":"bb"}
My expectation is the serializer picked up as one is used to with Web MVC. The docs (neither Spring Framework or Boot) give me any indication that it should not be the case with the new Jackson2JsonDecoder and encoder classes.
Demo project with test is attached.
InitializrSpringbootProject.zip
Ok, digging deeper into this topic I recognize that there's a WebFluxConfigurer which can be used to achieve my goal by passing the preconfigured ObjectMapper to encoder / decoder and than to web flux.
From an end users point of view wouldn't it be nice to have that automatically as Spring Boot with Web MVC already does?
@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().jackson2Encoder(encoder);
configurer.defaultCodecs().jackson2Decoder(decoder);
}
};
}
Duplicates #9166 ?
Think so, too!
Is there also a ticket to make those Encoders and Decoders register with WebTestClient? I was expecting that when I configure WebFluxConfigurer, WebTestClient should know them, too (it doesn't).
I can open a new ticket if it should…
It must be the exact same issue.
I'm not sure. There are maybe several issues here.
Given the additional configuration class above, the following @SpringBootTest partially works:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureWebTestClient
public class SomeControllerTest {
@Autowired
private WebTestClient client;
@Test
public void jsonShouldBeFormattedCorrectly() {
// That works as expected
this.client.get().uri("/someObject")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody().consumeAsStringWith(s -> Assert.assertThat(s, is(equalTo("{\"a\":\"aa\",\"b\":\"bb\"}"))));
}
@Test
public void typeShouldBeDeserialized() {
// That fails due to missing creator exception
this.client.get().uri("/someObject")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.returnResult(SomeObject.class)
.getResponseBody().subscribe(System.out::println);
}
}
The typeShouldBeDeserialized test fails with com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Can not construct instance of com.example.demo.SomeObject even with a Deserializer in place.
Next problem complex is the @WebFluxTest: As it doesn't look at anything beside WebFlux, it doesn't even look at the configuration at all.
Would be great if you have a look at the updated sample and decide wether to create a new ticket or not…
@michael-simons there are indeed several issues here and I think we can address them in a general way via #9166. We have a reference to your project now so we can review it at that time. If you want an issue focused on the client, feel free to create a separate issue. This one, as initially described is really a duplicate.
Most helpful comment
@michael-simons there are indeed several issues here and I think we can address them in a general way via #9166. We have a reference to your project now so we can review it at that time. If you want an issue focused on the client, feel free to create a separate issue. This one, as initially described is really a duplicate.