Reputation: 4636
I have created a custom provider that serializes my objects into JSON because the default Jackson serialization seemed to not work properly when using UTF-8 encoding (it was adding extra illegal characters that could not be decoded by the client).
Provider:
@Provider
@Produces(MediaType.APPLICATION_JSON+"; charset=UTF-8")
public class JsonSerializer implements MessageBodyWriter<ResponseModel> {
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public long getSize(ResponseModel t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return 0;
}
@Override
public void writeTo(ResponseModel entity, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
Gson gson = new GsonBuilder().setDateFormat("dd/MM/yyyy HH:mm:ss").create();
JSONObject output = new JSONObject();
output = (JSONObject) JSONValue.parse(gson.toJson(entity));
entityStream.write(output.toString().getBytes());
entityStream.flush();
}
}
Here is my jersey servlet web.xml:
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<!-- Register resources and providers under com.vogella.jersey.first package. -->
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>gr.modus.ext</param-value>
</init-param>
<!--init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param-->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>gr.modus.ext</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Here is a sample logic from a web service method:
ResponseModel<AnnouncementStatus> rm = new ResponseModel<AnnouncementStatus>();
rm.setData(AnnouncementUtils.getStatuses(userId));
rm.setSuccess(true);
return Response.ok(rm).build();
Whenever I call this method, it goes through my JsonSerializer correctly but it gives the following internal server error:
java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:260) at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:781) at com.sun.faces.application.ByteArrayWebOutputStream.writeTo(ByteArrayWebOutputStream.java:112) at com.sun.faces.application.ViewHandlerResponseWrapper.flushToWriter(ViewHandlerResponseWrapper.java:162)
The weird thing is that everything works correctly when my annotation produces just MediaType.APPLICATION_JSON
. However the response data isn't correctly encoded so I was forced to add the encoding manually, and now I have this problem...
Upvotes: 0
Views: 329
Reputation: 32397
entityStream.write(output.toString().getBytes())
is wrong. You should use getBytes(StandardCharsets.UTF_8)
(although it seems a roundabout way of getting there, even then. Can't you use write
?)
JSON is always serialised with UTF-8, so there is no need to add "; charset=UTF-8"
to the content-type.
Upvotes: 1