Search code examples
javaspring-bootspring-webfluxjackson2spring-webclient

WebClient giving MediaType not supported Exception when using class with custom getter setter as RequestBody


I have class all classes in my spring Webflux Application which has getter/setters without get and set prefix and setter return this. Hence i have also defined my custom Jackson Configuration for that which works fine with all my controllers successfully for serialising deserialising.

My Jackson Config

@Configuration
public class JacksonObjectMapperConfiguration implements Jackson2ObjectMapperBuilderCustomizer {

  @Override
  public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
    jacksonObjectMapperBuilder
      .serializationInclusion(NON_NULL)
      .failOnUnknownProperties(false)
      .visibility(FIELD, ANY)
      .modulesToInstall(new ParameterNamesModule(PROPERTIES));
  }
}

My Request Class

@Accessors(chain = true, fluent = true)
@Getter
@Setter // from project Lombok
public class Test {
  private String a;
  private List<String> b;
}

Now if I make request using webclient like below

  public Mono<Void> postRequest(String a, List<String> b) {
    Webclient webclient = Webclient.create();
    return webClient.post()
      .uri("some_url")
      .contentType(MediaType.APPLICATION_JSON)
      .bodyValue(new Test().a(a).b(b))
      .retrieve()
      .bodyToMono(Void.class);
  }

I get an exception like below

org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/json' not supported for bodyType=<Classpath>

but instead if i pass a Map like below, it works.

  public Mono<Void> postRequest(String a, List<String> b) {
    Webclient webclient = Webclient.create();
    return webClient.post()
      .uri(format("some_url")
      .contentType(MediaType.APPLICATION_JSON)
      .bodyValue(new HashMap<String,Object>(){{put("a",a);put("b",b);}})
      .retrieve()
      .bodyToMono(Void.class);
  }

I have tried removing @Accessor annotation and creating the getter setter myself but still it doesn't works.

I think the exception is occurring due to some deserialisation issue. I am not sure though. Jackson works fine with all my controllers in the application.

How can i make the first case work where i can provide a class as body instead of a Map?


Solution

  • Creating Webclient like below solved my issue.

      public WebClient webClient() {
        WebClient.Builder builder = WebClient.builder();
        builder.exchangeStrategies(EXCHANGE_STRATEGIES)
          .defaultHeader("content-type", "application/json");
        return builder.build();
      }
    
      public static final ObjectMapper GSON_LIKE_OM = new ObjectMapper()
        .setSerializationInclusion(NON_NULL)
        .setVisibility(FIELD, ANY)
        .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
        .registerModule(new ParameterNamesModule(PROPERTIES));
    
      public static final ExchangeStrategies EXCHANGE_STRATEGIES = ExchangeStrategies
        .builder()
        .codecs(clientDefaultCodecsConfigurer -> {
          clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(GSON_LIKE_OM, APPLICATION_JSON));
          clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(GSON_LIKE_OM, APPLICATION_JSON));
        }).build();