7
votes

using Java 11, SpringBoot 2, WebFlux, WebClient and Jackson

trying to use Spring WebClient to consume a Web service endpoint that returns XML, content type: 'text/xml;charset=UTF-8'

Jackson XML dependency in the project's pom.xml:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.9</version>
</dependency>

WebClient code that triggers a request to external API and builds the response:

        WebClient.builder()
                .baseUrl(url)
                .build()
                .get()
                .uri(builder.toUriString(), 1L)
                .accept(TEXT_XML)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML_VALUE)
                .acceptCharset(Charset.forName("UTF-8"))
                .exchange()
                .flatMap(x -> x.bodyToMono(ServiceResponse.class))
                .flatMap(x -> buildResponse(x));

ServiceResponse class (a simple POJO):

public class ServiceResponse {

    private String ack;
    private String version;
    private String timestamp;
// .. getters and setters

resulting error:

org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/xml;charset=UTF-8' not supported for bodyType=com.sample.service.model.ServiceResponse at org.springframework.web.reactive.function.BodyExtractors.lambda$readWithMessageReaders$12(BodyExtractors.java:201) ~[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE] at java.base/java.util.Optional.orElseGet(Optional.java:369) ~[na:na] at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:197) ~[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.web.reactive.function.BodyExtractors.lambda$toMono$2(BodyExtractors.java:85) ~[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.web.reactive.function.client.DefaultClientResponse.body(DefaultClientResponse.java:95) ~[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.web.reactive.function.client.DefaultClientResponse.bodyToMono(DefaultClientResponse.java:113) ~[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]

how to properly consume the type of response: Content-type 'text/xml;charset=UTF-8' ?

5
Jackson is for JSON. You need JAXB to work with XML. - Kartik
@guilhebl I am still facing this error. Did you find a solution for this? - user1578872

5 Answers

4
votes

Jackson XML is not supported at the moment by Spring Framework - see the dedicated issue. In the meantime, you can use Jaxb with Jaxb2XmlEncoder and Jaxb2XmlDecoder.

1
votes

Adding

.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) 

worked for me. MediaType Represents Internet Media Type that defined in the HTTP specification. For reference : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/MediaType.html

When I was trying write tc using WebTestClient in spring webflux, I faced this error. The unit test is in below section:

@Test
 public void testGetJobSummariesResBody() throws Exception{
 List<JobSummary> responseBody =
                testClient
                .get().uri("<uri-name>")
                .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
                .header(APPNAME_HEADER, "<header-name>")
                .exchange()
                .expectStatus().isOk()
                .expectBodyList(JobSummary.class)
                .returnResult()
                .getResponseBody();

        assertNotNull(responseBody.get(0).getJobType());
        assertNotEquals(0,responseBody.size());
    }
0
votes

I had a similar case, when i was trying to return "plain/text" but the object was being resolved into a json format (so not really a text). I suppose spring was doing some validation of the response contenty-type and body u set. My actual response was like that:

Mono.just(quote.getQuote())
                .flatMap(s -> ServerResponse.ok()
                        .contentType(MediaType.TEXT_PLAIN)
                        .syncBody(s)
                );

but also acceptable was:

Mono.just(jsonQuote)
                .flatMap(s -> ServerResponse.ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .syncBody(s)
                );
0
votes

In my case the problem was that I forgot to set the Accept header and the default behavior of the server was to return XML.
Setting it to MediaType.APPLICATION_JSON resolved the issue and the server started returning JSON.

-1
votes

Another situation when confusing UnsupportedMediaTypeException is thrown. Lets assume theres producing api that listens both http/80 and https/443. However its configured so that no content is served over http. Instead this returns HTTP 301 redirect message with some html content having content-type text/html. By default WebClient does not follow 301 redirect and instead it tries to parse returned html message into assumed class. This fails obviously and produces UnsupportedMediaTypeException exception. This may be further confused by the fact that Postman by default follows 301 redirect and does it in a completely transparent way. Leaving impression that you get expected content via http request.

Solution: use https request.