2016-10-30 8 views
0

Я хочу сделать глобальную проверку для каждого запроса. Поэтому я использую ContainerRequestFilter (без @PreMatching) и бросаю WebApplicationException с ответом, содержащим объект ошибки, если проверка не передается.ContainerRequestFilter возвращает неверный тип содержимого для объекта

Моя проблема заключается в том, что тип содержимого ответа не соответствует заголовку запроса Accept. Но если я бросаю одно и то же исключение в свой ресурс, ответ содержит правильный тип контента.

Код:

Моя сущность:

@XmlRootElement(namespace = "http://www.mycompany.com/test") 
@XmlAccessorType(value = XmlAccessType.FIELD) 
public class TestEntity { 

    public TestEntity() { 
     this.key = "error"; 
    } 

    @XmlElement 
    private String key; 
} 

Мой фильтр:

@Named 
public class TestFilter implements ContainerRequestFilter { 
    private boolean globalError = true; 

    public void filter(final ContainerRequestContext requestContext) throws IOException { 
     if (globalError) { 
      throw new WebApplicationException(Response.status(422).entity(new TestEntity()).build()); 
     } 
    } 
} 

Мой ресурс:

@Named 
public class TestResource { 

    @GET 
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) 
    public void find() { 
     throw new WebApplicationException(Response.status(422).entity(new TestEntity()).build()); 
    } 
} 

Мои CXF конф iguration:

<jaxrs:server address="/rest/v1" id="test"> 
    <jaxrs:serviceBeans> 
     <ref bean="testResource" /> 
    </jaxrs:serviceBeans> 
    <jaxrs:providers> 
     <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" /> 
     <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" /> 
     <ref bean="testFilter" /> 
    </jaxrs:providers> 
</jaxrs:server> 

Тест:

Запрос:

GET http://localhost:8080/test-webapp/services/rest/v1/ HTTP/1.1 
Accept-Encoding: gzip,deflate 
Accept: application/json 
Host: localhost:8080 
Connection: Keep-Alive 
User-Agent: Apache-HttpClient/4.1.1 (java 1.5) 

Ответ с globalError=true:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:testEntity xmlns:ns2="http://www.mycompany.com/test"> 
     <key>error</key> 
</ns2:testEntity> 

Ответ с globalError=false:

{"key":"error"} 

Вопросы:

Почему реакция отличается? Как я могу это исправить?

ответ

1

по умолчанию на основе @pedrofb хорошо answer Я нашел более легким обход, используя ContainerRequestContext#getAcceptableMediaTypes:

Получить список типов носителей, приемлемых для ответа.

Возвращает:
только для чтения список запрошенных типов носителей ответа, отсортированных в соответствии с их добротностью, с самым высоким предпочтением первого.

Мой модифицированный фильтр:

@Named 
public class TestFilter implements ContainerRequestFilter { 
    private boolean globalError = true; 

    public void filter(final ContainerRequestContext requestContext) throws IOException { 
     if (globalError) { 
      MediaType mediaType = requestContext.getAcceptableMediaTypes().size() > 0 ? requestContext.getAcceptableMediaTypes().get(0) : null; 
      throw new WebApplicationException(Response.status(422).type(mediaType).entity(new TestEntity()).build()); 
     } 
    } 
} 
1

По умолчанию построитель ответов по умолчанию ContainerRequestFilter не использует заголовок accept для переопределения типа содержимого ответа. Его необходимо добавить тип содержимого в Response

throw new WebApplicationException(Response.status(422).type("applicati‌​on/json").entity(new TestEntity()).build() 

Одним из вариантов, чтобы получить желаемое поведение проверки заголовка до того набора .type в ответ исключения (используйте requestContext.abortWith() вместо сгенерирует исключение)

Это пример для установки application/json, если он найден в заголовке или тип возвращаемого

public class TestFilter implements ContainerRequestFilter { 
    private boolean globalError = true; 

    private String typeFromHeaders(ContainerRequestContext requestContext){ 
     List<String> acceptHeaders = requestContext.getHeaders().get("Accept"); 
     if (acceptHeaders != null){   
      for (String acceptHeader: acceptHeaders){ 
       if (acceptHeader.indexOf(MediaType.APPLICATION_JSON)>=0){ 
        return MediaType.APPLICATION_JSON; 
       } 
      } 
     } 
     return null; 
    } 
    public void filter(final ContainerRequestContext requestContext) throws IOException { 
     if (globalError) { 
      requestContext.abortWith(
        Response.status(422).type(typeFromHeaders(requestContext)).entity(new TestEntity()).build()); 
     } 
    } 
}