Spring Rest template – when the response is not opinionated.

Spring Rest template works out of the box when the response is JSON. It’s opinionated and easy. The trouble begins if you want to extract a response that is not JSON. In this case, the deep dive in knowing about message converters can make one dizzy.

In the opinionated case, to consume post to an API endpoint and consume the response can be as simple as

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(webhookURL);
URI ApiUrl = new URI(builder.buildAndExpand(urlParams).toUri().toString());
ResponseEntity<Object> objectResponseEntity = integrationAppRestClient.postForEntity(ApiUrl, payloadObject, Object.class);
Object body = objectResponseEntity.getBody();
                return objectResponseEntity.getStatusCodeValue();

The above is Build API Url -> Post Response – > get status


But if the verbose non-opinionated – say if you want to consume a html response – will be

Charset utf8 = Charset.forName("UTF-8");
                MediaType mediaType = new MediaType("text", "html", utf8);
                headers.setContentType(mediaType);
                HttpEntity<Object> httpEntity = new HttpEntity<>(postResponse, headers);                

                UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(webhookURL);

                ApiUrl = new URI(builder.buildAndExpand(urlParams).toUri().toString());            

                MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
                converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_HTML));
                integrationAppRestClient.getMessageConverters().add(converter);    
                
              	ResponseEntity<String> objectResponseEntity = integrationAppRestClient.exchange(ApiUrl, HttpMethod.POST, httpEntity, String.class);
                
                return objectResponseEntity.getStatusCodeValue();

Set the headers -> Create an HttpEntity as you are now going to add (headers, payload) together as an entity -> set the converters that will consume the html response -> make sure the final respone can consume the HTML as string so set String as return type

So that’s the overhead.


In the spring-web HttpMessageConverterExtractor class, here is where most of the magic takes place and most of the exceptions that “there was no suitable converter found for response” will originate from.

public T extractData(ClientHttpResponse response) throws IOException {
        MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
        if (responseWrapper.hasMessageBody() && !responseWrapper.hasEmptyMessageBody()) {
            MediaType contentType = this.getContentType(responseWrapper);

            try {
                Iterator var4 = this.messageConverters.iterator();

                while(var4.hasNext()) {
                    HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next();
                    if (messageConverter instanceof GenericHttpMessageConverter) {
                        GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter;
                        if (genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) {
                            if (this.logger.isDebugEnabled()) {
                                ResolvableType resolvableType = ResolvableType.forType(this.responseType);
                                this.logger.debug("Reading to [" + resolvableType + "]");
                            }

                            return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper);
                        }
                    }

                    if (this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) {
                        if (this.logger.isDebugEnabled()) {
                            String className = this.responseClass.getName();
                            this.logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");
                        }

                        return messageConverter.read(this.responseClass, responseWrapper);
                    }
                }
            } catch (HttpMessageNotReadableException | IOException var8) {
                throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", var8);
            }

            throw new RestClientException("Could not extract response: no suitable HttpMessageConverter found for response type [" + this.responseType + "] and content type [" + contentType + "]");
        } else {
            return null;
        }
    }

Leave a comment

Design a site like this with WordPress.com
Get started