How can I tell RestTemplate to POST with UTF-8 encoding?

Solution 1:

You need to add StringHttpMessageConverter to rest template's message converter with charset UTF-8. Like this

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters()
        .add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));

Solution 2:

(Adding to solutions by mushfek0001 and zhouji)

By default RestTemplate has ISO-8859-1 StringHttpMessageConverter which is used to convert a JAVA object to request payload.

Difference between UTF-8 and ISO-8859:

UTF-8 is a multibyte encoding that can represent any Unicode character. ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters. Both encode ASCII exactly the same way.

Solution 1 (copied from mushfek001):

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters()
        .add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));

Solution 2:

Though above solution works, but as zhouji pointed out, it will add two string converters and it may lead to some regression issues.

If you set the right content type in http header, then ISO 8859 will take care of changing the UTF characters.

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

or

// HttpUriRequest request
request.addHeader("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE);

Solution 3:

The answer by @mushfek0001 produce two StringHttpMessageConverter which will send two text/plain and */*, such as the debug picture.

enter image description here

Even the Accept header of client will be:

text/plain, text/plain, */*, */*

So the better one is remove the ISO-8859-1 StringHttpMessageConverter and use single UTF-8 StringHttpMessageConverter.

Use this:

RestTemplate restTemplate = new RestTemplate();
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
stringHttpMessageConverter.setWriteAcceptCharset(true);
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
    if (restTemplate.getMessageConverters().get(i) instanceof StringHttpMessageConverter) {
        restTemplate.getMessageConverters().remove(i);
        restTemplate.getMessageConverters().add(i, stringHttpMessageConverter);
        break;
    }
}

Solution 4:

Adding new StringHttpMessageConverter won't help. In existing StringHttpMessageConverter we need to set writeAcceptCharset to false and build httpheader with charset we want.

RestTemplate restTemplate = new RestTemplate();
   List<HttpMessageConverter<?>> c = restTemplate.getMessageConverters();
        for(HttpMessageConverter<?> mc :c){
            if (mc instanceof StringHttpMessageConverter) {
                StringHttpMessageConverter mcc = (StringHttpMessageConverter) mc;
                mcc.setWriteAcceptCharset(false);
            }
   }

  HttpHeaders headers = new HttpHeaders();
  headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
  headers.setAcceptCharset(Arrays.asList(Charset.forName("UTF-8")));
  HttpEntity<String> entity = new HttpEntity<String>(jsonPayload, headers);

  restTemplate.postForEntity(postResourceUrl, entity, String.class);