javaresttemplatehttpentity

HttpMessageNotReadableException: JSON parse error: Unrecognized token '嬀崀'


I am calling an endpoint via RestTemplate as follows:

   SSLContext sslContext = SSLContexts.createSystemDefault();
   SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
   HttpClient client = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
   ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);

   HttpEntity<String> entity = new HttpEntity<>(requestJson, headers());
   Object[] response = restTemplate.postForObject(uri, entity, Object[].class);

I have verified that the JSON String in the entity object is valid by copying it and using it in a cURL request to the same endpoint without any error. The same headers and authorization token were used in this request too.

When I execute the POST, I get back the following error:

Error while extracting response for type [class [Ljava.lang.Object;] and content type [application/json;charset=utf-16]
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token '嬀崀': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token '嬀崀': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
     at [Source: (InputStreamReader); line: 1, column: 3]

My accept and content-type headers are both set to application/json. From examining the output from cURL, I see that there are no Chinese characters in the response body.

The response headers are as follows:

Connection →keep-alive
Content-Encoding →gzip
Content-Type →application/json; charset=utf-8
Date → xxx
Transfer-Encoding →chunked
Vary →Accept-Encoding

When I make the request with the responseType set to String.class or Object.class, the response is Chinese characters:

restTemplate.postForObject(uri, entity, String.class);
嬀崀

I am expecting that this call should return an empty array [].

When I change the requestJson String to one which should serve back a non-empty array, I get back hundreds of Chinese characters instead of just two.

How can I decode the response to get valid data like when I use cURL?

edit:

I'm not sure how this is related, but the bytecode for the chars in an empty array [] are 91 and 93, and the bytecode for the two Chinese characters is 0, 91, 0, 93.


Solution

  • The API is serving back UTF-8 content when I call it from cURL, but when I call the API programmatically it is serving back UTF-16LE despite my request headers asking for UTF-8 explicitly.

    I will need to do some de-/en-coding games, but the following allows me to observe the valid, expected response JSON:

    ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity(uri, entity, byte[].class);
       
    byte[] bytes = responseEntity.getBody();
    
    String json = new String(bytes, StandardCharsets.UTF_16LE);
    
    FooBar[] fooBar = objectMapper.readValue(json, FooBar[].class);