Search code examples
javaspring-bootkotlinwebclientspring-webflux

Parse text/html response to xml with web-client in spring-boot


I'm calling an API which returns xml response with content-type "text/html" When I try to parse the response in xml class, I'm getting the error message:

Content type 'text/html' not supported for bodyType=Response

Actual response of API

<?xml version='1.0' encoding='UTF-8'?>
<response version="1.0">
    <responseCode>200</responseCode>
    <responseMsg>some message</responseMsg>
</response>

I added custom codec to solve this but somehow it doesn't work. when I added that I got json decoding error:

JSON decoding error: Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')

Here is my code: API calling

return webClient.get()
            .uri { builder ->
                builder.path("/apiPath")
                    .queryParams(queryParams)
                    .build()
            }
            .retrieve()
            .onStatus({ it != HttpStatus.OK }) {
                RuntimeException("").toMono()
            }
            .bodyToMono(Response::class.java)
            .doOnError {
                logger.error { "Error" }
            }.block()

web client builder

    @Bean
    fun webClient(): WebClient = WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build())
        .baseUrl("apiUrl")
        .build()

    private fun acceptedCodecs(clientCodecConfigurer: ClientCodecConfigurer) {
        clientCodecConfigurer.customCodecs().register(Jackson2JsonEncoder(ObjectMapper(), TEXT_HTML))
        clientCodecConfigurer.customCodecs().register(Jackson2JsonEncoder(ObjectMapper(), TEXT_HTML))
    }

Response class

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "response")
data class Response(
    @XmlElement
    val responseCode: String = "2000",
    @XmlElement
    val responseMsg: String = "OK",
)

I believe adding custom codec part needs to be modified but I'm not getting what exactly have to change. Please let me know where I'm doing wrong. Thank you.

Edit: I tried to modify exchangeStrategies for XML like this

clientCodecConfigurer.defaultCodecs().jaxb2Decoder(Jaxb2XmlDecoder())
clientCodecConfigurer.defaultCodecs().jaxb2Encoder(Jaxb2XmlEncoder())

but got the same error

message : Content type 'text/html' not supported for bodyType=Response

Solution

  • Jaxb2XmlDecoder default constructor doesn't have "text/html" by default. You need to pass it to using Jaxb2XmlDecoder(MimeType... supportedMimeTypes) For example:

    clientCodecConfigurer.defaultCodecs().jaxb2Decoder(
    Jaxb2XmlDecoder(MimeTypeUtils.APPLICATION_XML, MimeTypeUtils.TEXT_XML, MediaType("application", "*+xml"), MimeTypeUtils.TEXT_HTML))