5

A web API is responding to a request with Content-Type:text/plain; charset=utf-8, but the messageis formatted as if it were a JSON, eg.

{
"total": 168,
"page": 0,
"pageCount": 1,
...
}

In Spring, this message is processed with a RestTemplate and the JSON is automagically mapped into a ModelDto POJO,

restTemplate.getForObject(url, ModelDto::class.java) 

This gives the following error:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class api.ModelDto] and content type [text/plain;charset=utf-8]

Is there any way to have spring treat this message as if it were a JSON and parse it as such, despite the Content-Type being plaintext?

Adam Hughes
  • 14,601
  • 12
  • 83
  • 122

1 Answers1

8

UPDATED

There's no need to create a custom HttpMessageConverter since AbstractHttpMessageConverter has a method setSupportedMediaTypes which can be used to change supported media type:

MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));
restTemplate.getMessageConverters().add(0, converter);

I think it's possible via implementing own HttpMessageConverter<T>.

RestTemplate uses it to convert a raw response to some representation (for instance, POJO). Since it has a list of converters, it finds specific converter for a particular response by its type (e.g application/json, etc).

So your implementation of HttpMessageConverter<T> should be something like default MappingJackson2HttpMessageConverter but with changed supported media type:

public class MappingJackson2HttpMessageConverter2 extends AbstractJackson2HttpMessageConverter {

    private String jsonPrefix;

    public MappingJackson2HttpMessageConverter2() {
        this(Jackson2ObjectMapperBuilder.json().build());
    }

    public MappingJackson2HttpMessageConverter2(ObjectMapper objectMapper) {
        // here changed media type
        super(objectMapper, MediaType.TEXT_PLAIN);
    }

    public void setJsonPrefix(String jsonPrefix) {
        this.jsonPrefix = jsonPrefix;
    }

    public void setPrefixJson(boolean prefixJson) {
        this.jsonPrefix = (prefixJson ? ")]}', " : null);
    }


    @Override
    protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
        if (this.jsonPrefix != null) {
            generator.writeRaw(this.jsonPrefix);
        }
        String jsonpFunction =
                (object instanceof MappingJacksonValue ? ((MappingJacksonValue) object).getJsonpFunction() : null);
        if (jsonpFunction != null) {
            generator.writeRaw("/**/");
            generator.writeRaw(jsonpFunction + "(");
        }
    }

    @Override
    protected void writeSuffix(JsonGenerator generator, Object object) throws IOException {
        String jsonpFunction =
                (object instanceof MappingJacksonValue ? ((MappingJacksonValue) object).getJsonpFunction() : null);
        if (jsonpFunction != null) {
            generator.writeRaw(");");
        }
    }

}

Then you can add this to RestTemplate object:

restTemplate.getMessageConverters().add(0, new MappingJackson2HttpMessageConverter2());
waded
  • 68
  • 5
Mykola Yashchenko
  • 5,103
  • 3
  • 39
  • 48
  • Thanks, let me try this out and will get back – Adam Hughes Mar 25 '18 at 15:35
  • 1
    Looks like another approach is to just change in the inbound header. https://stackoverflow.com/questions/42592440/how-to-change-response-http-header-in-get-request-by-spring-resttemplate?rq=1 – Adam Hughes Mar 25 '18 at 16:22
  • Updated my answer – Mykola Yashchenko Mar 25 '18 at 18:53
  • @MykolaYashchenko `MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(Arrays.asList(TEXT_PLAIN, MediaType.APPLICATION_JSON)); restTemplate.getMessageConverters().add(0, converter);` I have added the TEXT_PLAIN in converter still facing the same issue. `[class com.fasterxml.jackson.databind.JsonNode] and content type [text/plain;charset=ISO-8859-1];` – Nagendra Nigade Aug 28 '19 at 11:06
  • @NagendraNigade I guess the reason is that "text/plain;charset=ISO-8859-1" is not the same as "text/plain" – Mykola Yashchenko Aug 29 '19 at 12:04
  • try to do `converter.setSupportedMediaTypes(Arrays.asList("text/plain;charset=ISO-8859-1", MediaType.APPLICATION_JSON))` – Mykola Yashchenko Aug 29 '19 at 12:05
  • @MykolaYashchenko : thanks! your original answer worked! – Nagendra Nigade Aug 29 '19 at 12:08