0

My micro service needs to communicate with 2 different services over HTTP. 1 has an API contract with snake_case JSON, while the other uses camelCase. How can I configure WebFlux to deserialize and serialize JSON with a certain Jackson ObjectMapper on a set of functional endpoints, while use another one on different endpoints?

The WebFlux documentation shows how to wire in another ObjectMapper, but this applies to all the endpoints of my API. So right now either all my JSON in snake_case or in camelCase. Cant find any resource to solve this issue, but it must be doable right?

Update: to make it clear I want to configure the web server which receives the requests from other services, not the webclient for sending http requests myself. I know how to do the latter.

logi0517
  • 813
  • 1
  • 13
  • 32
  • This might help you, took me 1 min to google https://stackoverflow.com/questions/43769301/how-to-customize-springwebflux-webclient-json-deserialization – Toerktumlare Aug 29 '19 at 21:12
  • this customizes the webclient HTTP coding, I already do this, but this is not what I need. The stuff I linked is about customizing the encoding for the incoming request to the server, and their responses. – logi0517 Aug 29 '19 at 21:24

2 Answers2

0

you can use the @JsonNaming annotation on the classes you want to serialize/deserialize and specify what type of naming strategy you want.

jackson-advanced-annotations

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • thanks for the tip! sadly there are plenty of data classes the APIs share – logi0517 Aug 30 '19 at 05:07
  • well i am pretty convinced there is no built in way of setting specific serialization/deserialization basen on path mapping alone. So good luck then – Toerktumlare Aug 30 '19 at 20:23
  • I did find a workaround solution. But I only have a proof of concept yet. Once I clean it up and bake it into my service, i'll post it here. – logi0517 Sep 01 '19 at 07:55
0

Okay, so this is not the cleaned up solution, I will use this solution from our library, but the basic gist of my work around looks like this:

@Controller
public class Handler {

    private ObjectMapper mapper;

    public Handler(@Qualifier("snakeCaseWrapper") ObjectMapper mapper) {
        this.mapper = mapper;
    }

    Mono<ServerResponse> returnUser(final ServerRequest request) {
        //REQUEST DESERIALIZATION
        var messageReader = new DecoderHttpMessageReader<>(new Jackson2JsonDecoder(mapper));
        var configuredRequest = ServerRequest.create(request.exchange(), List.of(messageReader));

        //RESPONSE SERIALIZATION
        return configuredRequest.bodyToMono(UserDto.class)
                                .map(userDto -> {
                                    try {
                                        return mapper.writeValueAsString(userDto);
                                    } catch (JsonProcessingException e) {
                                        e.printStackTrace();
                                        //properly handle the error here
                                        return "";
                                    }
                                })
                                .flatMap(json -> ServerResponse.ok()
                                                               .contentType(MediaType.APPLICATION_JSON)
                                                               .body(BodyInserters.fromObject(json))
                                );
    }
}

This is the only way I could find to programatically choose which kind of ObjectMapper I want to use for a specific endpoint/handler method for request deserialization. For response serialization, the trick was to first use the ObjectMapper to serialize the response body to a String, and put that String into the response with BodyInserters.fromObject(json) .

It works, so I'm happy with it.

logi0517
  • 813
  • 1
  • 13
  • 32