Java JSON String problem encoding Multipart

Tags: , , ,



I’m developing a REST API that receives a MultipartFormDataInput object (org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput), this comes from a form-data Vue.js app. On the data field comes a json string that contains latin accent characters (á, é, í, ó, ú, ñ). When print the json data in Java I get this:

Original Json string

{
  "code": "123456789",
  "form": "test",
  "pot": "special character  ñ",
  "categoria": "acción",
  "propiedad": "algún",
  "diligencia": "ábaco",
  "actual": "grabé",
  "pais":  "Abstraído",
  "vivio_otro_pais_cual": "word without special characters... OK  1 2 3<>?!@#$%^&*()_+"
}

Json string received in Java

11:04:32,086 INFO  [stdout] (default task-1) JSON VALUES.... {
11:04:32,087 INFO  [stdout] (default task-1)   "code": "123456789",
11:04:32,087 INFO  [stdout] (default task-1)   "form": "test",
11:04:32,087 INFO  [stdout] (default task-1)   "pot": "special character  ??",
11:04:32,087 INFO  [stdout] (default task-1)   "categoria": "acci??n",
11:04:32,087 INFO  [stdout] (default task-1)   "propiedad": "alg??n",
11:04:32,087 INFO  [stdout] (default task-1)   "diligencia": "??baco",
11:04:32,087 INFO  [stdout] (default task-1)   "actual": "grab??",
11:04:32,087 INFO  [stdout] (default task-1)   "pais":  "Abstra??do",
11:04:32,087 INFO  [stdout] (default task-1)   "vivio_otro_pais_cual": "word without special characters... OK  1 2 3<>?!@#$%^&*()_+"
11:04:32,087 INFO  [stdout] (default task-1) }

11:04:32,088 INFO  [stdout] (default task-1) JSON ENCODING.... {
11:04:32,088 INFO  [stdout] (default task-1)   "code": "123456789",
11:04:32,088 INFO  [stdout] (default task-1)   "form": "test",
11:04:32,088 INFO  [stdout] (default task-1)   "pot": "special character  ??",
11:04:32,088 INFO  [stdout] (default task-1)   "categoria": "acci??n",
11:04:32,088 INFO  [stdout] (default task-1)   "propiedad": "alg??n",
11:04:32,088 INFO  [stdout] (default task-1)   "diligencia": "??baco",
11:04:32,088 INFO  [stdout] (default task-1)   "actual": "grab??",
11:04:32,088 INFO  [stdout] (default task-1)   "pais":  "Abstra??do",
11:04:32,088 INFO  [stdout] (default task-1)   "vivio_otro_pais_cual": "word without special characters... OK  1 2 3<>?!@#$%^&*()_+"
11:04:32,088 INFO  [stdout] (default task-1) }

What can i do to receive the string with latin special characters?

My code (end point):

@POST
@Path("/testEncoding")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response testEncoding(@Context HttpHeaders headers, MultipartFormDataInput  multipart){
    return interfaceOperationService.testEncoding(headers, multipart);
}

Implementation:

public Response testEncoding(HttpHeaders headers, MultipartFormDataInput multipart) {

    try {
                
        String dataJson = multipart.getFormDataPart("data", String.class, null);
        String valorCodificado = new String (dataJson.getBytes(StandardCharsets.US_ASCII), StandardCharsets.UTF_8);
        System.out.println("JSON VALUES.... " + dataJson);
        System.out.println("JSON ENCODING.... " + valorCodificado);
                
        StringBuilder sb = new StringBuilder();
        for (String header : headers.getRequestHeaders().keySet()) {
            sb.append(header + ":" + headers.getRequestHeader(header) + "n");
        }        
        
        System.out.println(sb.toString());
                
        return Response.status(200).entity(valorCodificado).build();
    
    } catch (Exception e) {
        // TODO: handle exception
        return Response.status(500).entity("ERROR").build();
    }
}

and pom dependency:

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-multipart-provider</artifactId>
    <version>4.5.8.Final</version>
    <scope>provided</scope>
</dependency>

Answer

So in multipart, each body part is its own separate entity with its own separate content-type. If you don’t set the content-type for each part in the client request, it is assumed to be text/plain. In the case of RESTEasy implementation, it is text/plain; charset=ISO-8859-1.

InputPart.DEFAULT_CONTENT_TYPE_PROPERTY
If no content-type header is sent in a multipart message part “text/plain; charset=ISO-8859-1” is assumed.

A lot of clients are not able to set the content-type header for each part. So what you should do is set the content-type header for them. For this part, you want it to be application/json; chartset=utf-8. How you set the header is by getting the InputPart from the MultiPartFormDataInput. Instead of using the getFormDataPart() method, use the getFormDataMap() method to get a Map<String, List<InputPart>> return type. From there, get the InputPart and call InputPart#setMediaTye(), then you can get the data with one of the InputPart#getBody() variants. Something like (not tested):

Map<String, List<InputPart>> inputParts = multipart.getFormDataMap();
List<InputPart> dataParts = inputParts.get("data");
if (dataParts != null && !dataParts.isEmpty()) {
    InputPart dataPart = dataParts.get(0);
    dataPart.setMediaType(MediaType.APPLICATION_JSON + "; chartset=utf-8");
    String dataPartJson = dataPart.getBody(String.class, null);
    // of if you make a POJO the data will get deserialized by Jackson
    DataPojo dataPartPogo = dataPart.getBody(DataPojo.class, null);
}


Source: stackoverflow