Jersey seems to fail when returning JSON...
This:
@GET
@Produces( MediaType.APPLICATION_JSON + \";charset=UTF-8\")
public List getMyObje
SRGs suggestion works like a charm. However, since Jersey 2.0 the interfaces are slightly different, so we had to adapt the filter a little bit:
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
MediaType type = response.getMediaType();
if (type != null) {
String contentType = type.toString();
if (!contentType.contains("charset")) {
contentType = contentType + ";charset=utf-8";
response.getHeaders().putSingle("Content-Type", contentType);
}
}
}
}
SRGs and martins solution worked well for me.
However, I had to apply the following changes to the filter:
If the client does a request with an Accept header, Jersey adds a quality factor to the content type. This looks as follows:
No problem: request without Accept header:
curl -i http://www.example.com/my-rest-endpoint
response.getMediaType().toString()
is application/json
. We can simply append ;charset=utf-8
.
Problem: request with Accept header:
curl -i -H "Accept: application/json" http://www.example.com/my-rest-endpoint
response.getMediaType().toString()
is {application/json, q=1000}
. We cannot simply append ;charset=utf-8
, since this would lead to the following exception:
java.lang.IllegalArgumentException: Error parsing media type '{application/json, q=1000};charset=utf-8'
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:92) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:60) ~[na:na]
at javax.ws.rs.core.MediaType.valueOf(MediaType.java:179) ~[na:na]
...
Caused by: java.text.ParseException: Next event is not a Token
at org.glassfish.jersey.message.internal.HttpHeaderReader.nextToken(HttpHeaderReader.java:129) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.valueOf(MediaTypeProvider.java:110) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:90) ~[na:na]
... 193 common frames omitted
I'd suggest the following code to solve this problem:
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
MediaType type = response.getMediaType();
if (type != null) {
if (!type.getParameters().containsKey(MediaType.CHARSET_PARAMETER)) {
MediaType typeWithCharset = type.withCharset("utf-8");
response.getHeaders().putSingle("Content-Type", typeWithCharset);
}
}
}
}
I had the same problem : i don't like adding the charset in the "@Produces" tag everywhere.
I found the solution right here : http://stephen.genoprime.com/2011/05/29/jersey-charset-in-content-type.html
Basically, you just have to add a response filter that will add the charset (for example if the content type currently returned is either text, xml or json)
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
MediaType contentType = response.getMediaType();
response.getHttpHeaders().putSingle("Content-Type", contentType.toString() + ";charset=UTF-8");
return response;
}
}
And to register the filter :
ServletAdapter jerseyAdapter = new ServletAdapter();
jerseyAdapter.addInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.my.package.MyResponseFilter");
Works too with Guice, of course, for example in your class extending ServletModule :
final Map<String, String> parameters = new HashMap<String, String>();
parameters.put("com.sun.jersey.spi.container.ContainerResponseFilters", com.package.JerseyCharsetResponseFilter.class.getName());
serve("/*").with(GuiceContainer.class, parameters);