Кодировка символов Джерси / Отдых по умолчанию - PullRequest
16 голосов
/ 01 апреля 2011

Кажется, что Джерси отказывает при возвращении JSON ...Это:

@GET
@Produces( MediaType.APPLICATION_JSON + ";charset=UTF-8")
public List<MyObject> getMyObjects() {
    return ....;
}

необходимо для возврата в кодировке JSON utf-8.Если я использую только

@Produces( MediaType.APPLICATION_JSON)

, произойдет сбой и, например, немецкий умлат (üöä) будет возвращен неверным образом.

Два вопроса: 1 - Для стандарта JSON utf-8 ist - почему не с Джерси?2 - Могу ли я установить utf-8 для всего REST-сервлета, если приходит запрос JSON?Я использую Джерси 1.5 и CRest 1.0.1 на Android ...

Ответы [ 3 ]

16 голосов
/ 13 декабря 2013

предложение SRG работает как шарм.Однако, начиная с Джерси 2.0, интерфейсы немного отличаются, поэтому нам пришлось немного адаптировать фильтр:

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);
            }
        }
    }
}
7 голосов
/ 29 января 2013

У меня была такая же проблема: мне не нравится добавлять кодировку в тег "@Produces" везде.

Я нашел решение прямо здесь: http://stephen.genoprime.com/2011/05/29/jersey-charset-in-content-type.html

По сути, вам просто нужно добавить фильтр ответов, который добавит кодировку (например, если в настоящее время возвращается тип содержимого text, xml или 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;
    }
}

И зарегистрировать фильтр:

ServletAdapter jerseyAdapter = new ServletAdapter();
jerseyAdapter.addInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.my.package.MyResponseFilter"); 

Конечно, работает и с Guice, например, в вашем классе, расширяющем 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);
3 голосов
/ 14 марта 2015

Решения SRG и martins хорошо сработали.

Однако мне пришлось применить следующие изменения к фильтру:

Если клиент делает запрос с заголовком Accept, Джерси добавляетфактор качества для типа контента.Это выглядит следующим образом:

Нет проблем: запрос без заголовка Accept:

curl -i http://www.example.com/my-rest-endpoint

response.getMediaType().toString() - application/json.Мы можем просто добавить ;charset=utf-8.

Проблема: запрос с заголовком Accept:

curl -i -H "Accept: application/json" http://www.example.com/my-rest-endpoint

response.getMediaType().toString() равен {application/json, q=1000}.Мы не можем просто добавить ;charset=utf-8, так как это приведет к следующему исключению:

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

Я бы предложил следующий код для решения этой проблемы:

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);
            }
        }
    }
}
...