javaspringspring-bootjacksonjackson-databind

Content type 'application/json' not supported for bodyType=com.fasterxml.jackson.databind.JsonNode


So Im using spring gateway to build a proxy like service and one job is to process the response and update it, so accordingly I wrote a gateway filter but it seems like it's not working as I expected.

import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

@Slf4j
@Component
public class ResponseTransformationGatewayFilterFactory extends AbstractGatewayFilterFactory<ResponseTransformationGatewayFilterFactory.Config> {

    public ResponseTransformationGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        ModifyResponseBodyGatewayFilterFactory.Config modifyConfig = new ModifyResponseBodyGatewayFilterFactory.Config();
// used string.class but same issue
        modifyConfig.setRewriteFunction(JsonNode.class, JsonNode.class, (exchange, originalResponseBody) -> {
            // Transform the response body
            JsonNode transformedBody = transformResponseBody(originalResponseBody);
            return Mono.just(transformedBody);
        });
        return new ModifyResponseBodyGatewayFilterFactory(new ArrayList<>(), new HashSet<>(), new HashSet<>()).apply(modifyConfig);
    }

    private JsonNode transformResponseBody(JsonNode originalBody) {
        // we can get rid of fields here.

        return JsonResponseFilter.filter(originalBody, List.of("options"));

        // only add options with included providers

    }

    public static class Config {
    }
}

Error:

org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/json' not supported for bodyType=com.fasterxml.jackson.databind.JsonNode
    at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:205) ~[spring-webflux-6.0.12.jar:6.0.12]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ Body from UNKNOWN  [DefaultClientResponse]

Solution

  • So the issue was in my web client configuration, I need to add Jackson Decoder

          final ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
                    .codecs(configurer -> configurer.defaultCodecs()
                            .jackson2JsonDecoder(new Jackson2JsonDecoder(mapper))
                    )
                    .build();
    
            final var httpClient = HttpClient.create(provider)
                    .resolver(nameResolverSpec -> nameResolverSpec.cacheMaxTimeToLive(Duration.ofSeconds(60)))
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT)
                    .doOnConnected(connection -> {
                        connection.addHandlerLast(new ReadTimeoutHandler(TIMEOUT, TimeUnit.SECONDS));
                        connection.addHandlerLast(new WriteTimeoutHandler(TIMEOUT, TimeUnit.SECONDS));
                    });
    
            return WebClient.builder()
                    .baseUrl(baseUrl)
                    .exchangeStrategies(exchangeStrategies)
                    .defaultHeader(ACCEPT_HEADER, MediaType.ALL_VALUE)
                    .clientConnector(new ReactorClientHttpConnector(httpClient))
                    .build();