无法使用Jersey客户端过滤器覆盖响应标头

Gre*_*pff 4 java jersey

我正在尝试使用Jersey客户端API来使用第三方REST服务.我计划使用自动POJO反序列化从JSON响应转到Java对象.

不幸的是,第三方服务使用内容类型返回响应"text/javascript".我的Jersey客户端无法理解这应该被视为JSON对象并且无法反序列化该对象.

我写了一个简单的泽西服务器应用程序来验证通过更改内容类型"text/javascript",以"application/json"使deserialisation工作.

有了这些信息,我开始使用Jersey客户端过滤器来修改响应头.该代码来自该问题的作者的评论.事实上,问题似乎与我的完全相同 - 但是回答者错误地回答了问题,并展示了如何修改请求标头(而不是响应标头).原作者能够使用答案来创建他的解决方案,但是,似乎他所声明的解决方案无法工作.

过滤器代码是:

client.addFilter(new ClientFilter() {
  @Override public ClientResponse handle(ClientRequest cr) 
      throws ClientHandlerException {
    ClientResponse response = getNext().handle(cr); 
    response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); 
    return response;
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,当执行时,UnsupportedOperationException会引发:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.clear(Collections.java:1035)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:78)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:56)
at App$1.handle(App.java:49)
at com.sun.jersey.api.client.Client.handle(Client.java:648)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
at App.main(App.java:63)
Run Code Online (Sandbox Code Playgroud)

返回的标题似乎包含在不可修改的集合中.

然后我尝试将所有标头复制到新集合中,但是我无法看到将标头映射设置回响应.

最后,我想也许我可以创建一个ClientResponse包含我修改过的标题的新内容.但是,构造函数ClientResponse具有此签名:

public ClientResponse(int status, 
                      InBoundHeaders headers, 
                      InputStream entity, 
                      MessageBodyWorkers workers)  
Run Code Online (Sandbox Code Playgroud)

这是微不足道的复制status,headersentity从原来的变量.但是,我无法看到该workers字段的引用.

如何使用Jersey客户端过滤器修改响应头"text/javascript","application/json"以便我的POJO反序列化可以工作?

yeg*_*niy 7

在Jersey 2中,使用ClientConfig 注册ClientResponseFilter的实现,以便操纵传入响应的HTTP头.

例如,这似乎与Jersey 2.3.1一起用于操纵HTTP标头:

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.client.ClientRequestContext;

import org.glassfish.jersey.client.ClientConfig;

/* Ensure that there is an "application/xml" Content-Type header on
 * successful responses without a content type header. */
@Provider
public static class EnsureXmlContentTypeFilter implements ClientResponseFilter {
    @Override
    public void filter(ClientRequestContext requestContext,
                       ClientResponseContext responseContext) {
        if (200 == responseContext.getStatus() &&
            null == responseContext.getHeaderString(HttpHeaders.CONTENT_TYPE)) {

            responseContext.getHeaders().add(
                HttpHeaders.CONTENT_TYPE, "application/xml"
            );

        }
    }
}

private final ClientConfig config = new ClientConfig()
    // Registering this filter adds a "Content-Type: application/xml" 
    // header to each response that lacks Content-Type headers.
    .register(EnsureXmlContentTypeFilter.class)
;
private final Client client = ClientBuilder.newClient(config);
Run Code Online (Sandbox Code Playgroud)

关于过滤器和拦截器的Jersey文档并不完美,但它确实有一些链接到相关类的javadoc:https://jersey.java.net/documentation/latest/filters-and-interceptors.html

我从一个响应XML内容的服务获得XML响应,但缺少"Content-Type:application/xml"标头.可能更好的方法是注册MessageBodyReaders,但上面的方法在我使用该服务的API时有效.