Skip to content

@JsonComponent (JsonSerializer) not picked up for WebFlux serialization #9485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
michael-simons opened this issue Jun 12, 2017 · 7 comments
Closed
Labels
status: duplicate A duplicate of another issue

Comments

@michael-simons
Copy link
Contributor

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

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 12, 2017
@michael-simons
Copy link
Contributor Author

michael-simons commented Jun 12, 2017

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

@snicoll
Copy link
Member

snicoll commented Jun 12, 2017

Duplicates #9166 ?

@michael-simons
Copy link
Contributor Author

Think so, too!

@snicoll snicoll closed this as completed Jun 12, 2017
@snicoll snicoll added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 12, 2017
@michael-simons
Copy link
Contributor Author

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…

@snicoll
Copy link
Member

snicoll commented Jun 12, 2017

It must be the exact same issue.

@michael-simons
Copy link
Contributor Author

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…

InitializrSpringbootProject-update.zip

@snicoll
Copy link
Member

snicoll commented Jun 12, 2017

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

3 participants