Search code examples
javaspringhttp-headersgml-geographic-markup-lan

Parsing GML with Spring WebClient


I'm trying to read GML data from an OGC WFS source with Spring WebClient. However, the output format definition required by the service OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 leads to the following exception:

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/xml; subtype=gml/3.1.1;charset=UTF-8": Invalid token character '/' in token "gml/3.1.1"

A valid service link looks like this: https://www.luis.sachsen.de/arcgis/services/wasser/hochwassergefaehrdung/MapServer/WFSServer?service=WFS&request=GetFeature&typename=hochwassergefaehrdung:Gefaehrdung_bei_HQ100&srsName=urn:ogc:def:crs:EPSG::25833&VERSION=2.0.0&OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1&bbox=406311.9936150059,5651815.157329135,413721.3886195286,5663092.940723425,urn:ogc:def:crs:EPSG::25833

This is what the method looks like:

    private static final WebClient webClient = WebClient.create();

    public static String fetchRemoteText(String url) {
        try {
            return webClient.get().uri(url).retrieve().bodyToMono(String.class).doOnSuccess(body -> {
                if (body == null || body.isBlank()) {
                    log.info("Empty result returned.");
                }
            }).block(); 
        } catch (Exception e) {
            log.error("Error fetching from URL {}: {}", url, e.getMessage(), e);
            return null;
        }
    }

I've tried quite a lot of variations recommended by ChatGPT but none of them helped.


Solution

  • Your spring application reject your request, because of content type header. Spring web client has set of possible MIME types and "text/xml;%20subtype=gml/3.1.1" format is not supported. You need to override content-type header before processing. Instead of using WebClient.create(), instantiate the client with WebClient.builder() to allow for exchange of request headers. By the way from my experience is better to use doOnNext instead of doOnSuccess in your case.

    WebClient.builder()
        .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE)
        .filter(ExchangeFilterFunction.ofResponseProcessor(response -> 
            Mono.just(response.mutate()
                .headers(headers -> {
                    String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
                    if (contentType != null && contentType.contains("subtype=gml/")) {
                        headers.set(HttpHeaders.CONTENT_TYPE, "text/xml;charset=UTF-8");
                    }
                })
                .build())
        ))
        .build();