How can I tell RestTemplate to POST with UTF-8 encoding?
JsonSpringResttemplateJson Problem Overview
I'm having problems posting JSON with UTF-8 encoding using RestTemplate. Default encoding for JSON is UTF-8 so the media type shouldn't even contain the charset. I have tried to put charset in the MediaType but it doesn't seem to work anyway.
My code:
String dataJson = "{\"food\": \"smörrebröd\"}";
HttpHeaders headers = new HttpHeaders();
MediaType mediaType = new MediaType("application", "json", StandardCharsets.UTF_8);
headers.setContentType(mediaType);
HttpEntity<String> entity = new HttpEntity<String>(dataJson, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Boolean> formEntity = restTemplate.exchange(postUrl, HttpMethod.POST, entity, Boolean.class);
Json Solutions
Solution 1 - Json
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 - Json
(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 - Json
The answer by @mushfek0001 produce two StringHttpMessageConverter
which will send two text/plain
and */*
, such as the debug picture.
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 - Json
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);
Solution 5 - Json
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(StandardCharsets.UTF_16LE));
String response = restTemplate.getForObject(url, String.class);
Solution 6 - Json
Removing the existing converter, but with Java 8 (why do people still write Java 7 Code anyways?)
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
converters.removeIf(httpMessageConverter -> httpMessageConverter instanceof StringHttpMessageConverter);
converters.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
Solution 7 - Json
Better you should remove the StringHttpMessageConverter first before adding new. so this way you will have one instance of StringHttpMessageConverter in our MessageConverters list.
RestTemplate restTemplate = new RestTemplate();
final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator();
while (iterator.hasNext()) {
final HttpMessageConverter<?> converter = iterator.next();
if (converter instanceof StringHttpMessageConverter) {
iterator.remove();
}
}
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
Solution 8 - Json
Try this
restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(Charsets.UTF_8));
Solution 9 - Json
If you're using Spring Boot it will auto-configure RestTemplate with a high-priority UTF-8 charset StringHttpMessageConverter, if you use RestTemplateBuilder to create the RestTemplate instance. E.g. restTemplateBuilder.build()