【问题标题】:How can I override the decisions made during JAX-RS Content Negotiation?如何覆盖在 JAX-RS 内容协商期间做出的决定?
【发布时间】:2011-11-19 22:51:12
【问题描述】:

我使用 RESTEasy 2.2.1.GA 作为我的 JAX-RS 实现来创建客户端以连接到第三方服务提供商。 (如果重要,Education.com 的 REST API)

为了确保我没有错过重要的实现细节,这里提供了代码示例:

服务接口

@Path("/")
public interface SchoolSearch {

@GET
@Produces({MediaType.APPLICATION_XML})
Collection<SchoolType> getSchoolsByZipCode(@QueryParam("postalcode") int postalCode);
}

调用类

public class SimpleSchoolSearch {

public static final String SITE_URL = "http://api.education.com/service/service.php?f=schoolSearch&key=****&sn=sf&v=4";

SchoolSearch service = ProxyFactory.create(SchoolSearch.class, SITE_URL);

public Collection<SchoolType> getSchools() throws Exception {
    Collection<SchoolType> schools = new ArrayList<SchoolType>();
    Collection<SchoolType> response = service.getSchoolsByZipCode(35803);
    schools.addAll(response);
    return schools;

}
}

设置测试以进行此调用后,我执行并看到以下异常被抛出。

org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException: Unable to find JAXBContext for media type: text/html;charset="UTF-8"

据我了解,通过阅读 RESTEasy/JAX-RS 文档,当响应返回给客户端时,在解组数据之前,会确定使用哪种机制(内容协商??)用于解组。 (我认为我们在这里谈论的是 MessageBodyReader,但我不确定。)通过查看响应的正文,我看到返回的是格式正确的 XML,但是内容协商(通过 HTTP 标头内容类型确实是 text/html;charset ="UTF-8") 不允许 JAXB 解析文本。

我认为实现的行为是正确的,是服务出错了,但是,我不控制服务,但仍然想使用它。

这么说来:

我对为什么抛出异常的理解正确吗?

我该如何解决?

是否有一个简单的单行注释可以强制 JAXB 解组数据,还是我需要实现一个自定义 MessageBodyReader? (如果这甚至是要实现的正确类)。

谢谢!

跟进:

我只是想发布我对 Eiden 的回答所做的一些更改。我使用他的代码和Resteasy ClientExecutionInterceptor documentation 提供的信息创建了一个ClientExecutionInterceptor。我的最后一堂课看起来像

@Provider
@ClientInterceptor
public class SimpleInterceptor implements ClientExecutionInterceptor {

@Override
  public ClientResponse execute(ClientExecutionContext ctx) throws Exception {
      final ClientResponse response = ctx.proceed();
      response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML);
      return response;
  }
}

最大的不同是添加了@Provider 和@ClientExecutionInterceptor 注释。这应确保拦截器已正确注册。

另外,为了完整起见,我在测试中注册的拦截器略有不同。我用过:

        providerFactory.registerProvider(SimpleInterceptor.class);

【问题讨论】:

    标签: java rest jax-rs resteasy


    【解决方案1】:

    我确信这个问题有多种解决方案,但我只能想到一个。

    尝试使用 ClientExecutionInterceptor 设置内容类型:

    public class Interceptor implements ClientExecutionInterceptor {
    
        @Override
        public ClientResponse<?> execute(ClientExecutionContext ctx) throws Exception {
            final ClientResponse<?> response = ctx.proceed();
    
            response
                .getHeaders()
                .putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML);
    
            return response;
        }
    
    }
    
    public void getSchools() throws Exception {
        ResteasyProviderFactory.getInstance()
            .getClientExecutionInterceptorRegistry()
            .register( new Interceptor() );
    
        SchoolSearch service =
                ProxyFactory.create(SchoolSearch.class, SITE_URL);
    }
    

    【讨论】:

    • 这是一个非常简单的任务,一旦你把它布置成这样。
    【解决方案2】:

    我不知道任何此类注释,其他人可能会这样做,但解决方法是创建本地代理。创建一个控制器,使用 java.Net.URL.get() 返回您收到的答案,但修改标题。然后将您的客户端连接到本地代理控制器。

    【讨论】:

      猜你喜欢
      • 2011-07-12
      • 2011-02-19
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 2014-09-12
      相关资源
      最近更新 更多