首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何解决使用MultipartInput客户端API处理嵌套RESTEasy时引发的异常?

如何解决使用MultipartInput客户端API处理嵌套RESTEasy时引发的异常?
EN

Stack Overflow用户
提问于 2019-11-07 14:36:07
回答 1查看 737关注 0票数 1

我构建了以下JAX资源,它生成所需的响应对象,这个响应对象是multipart/混合嵌套的multipart/关联的(目前只有一个)嵌套的应用程序/json。

代码语言:javascript
运行
复制
@GET
@Path("test")
@Produces("multipart/mixed")
public Response test() {
  List<Entity> entities;
  ...
  final MultipartOutput multipartOutput = new MultipartOutput();
  entities.stream().map(entity -> {
    MultipartRelatedOutput multipartRelatedOutput = new MultipartRelatedOutput();
    multipartRelatedOutput.addPart(entity, MediaType.APPLICATION_JSON_TYPE);
    return multipartRelatedOutput;
  }).forEach(multipartRelatedOutput -> 
    multipartOutput.addPart(multipartRelatedOutput, MediaType.valueOf("multipart/related"))
  );
  return Response.ok(multipartOutput, MediaType.valueOf("multipart/mixed")).build();
}

此资源由用通过RESTEasy代理框架实现RESTEasy客户端API构建的客户端使用。响应的实体被读取为MultipartInput。每个部分的身体现在应该被读为MultipartRelatedInput。作为这在我的RESTEasy版本中是不可能的(但已经在4.5.5.Final中得到了修正),作为解决每个部分的身体被读为MultipartInput

代码语言:javascript
运行
复制
public void get()
{
  try (Response response = this.proxy.test();) {
    ...
    MultipartInput multipartInput = response.readEntity(MultipartInput.class);
    for (InputPart inputPart : multipartInput.getParts()) {
    try {
      //MultipartRelatedInput relatedInput = inputPart.getBody(MultipartRelatedInput.class, null); // not working with NPE with my RESTEasy version
      MultipartInput relatedInput = inputPart.getBody(MultipartInput.class, null);
      String json = relatedInput.getParts().get(0).getBodyAsString(); // fails
      // Entity entity = relatedInput.getParts().get(0).getBody(Entity.class, null); // also fails
    } catch (IOException exception) {}
  }
}

将封装的实体读取为JSON-String (为了简单起见,但也将其读取为具有实体的类类型的对象)失败,例外情况如下:

代码语言:javascript
运行
复制
Caused by: org.jboss.resteasy.spi.LoggableFailure: RESTEASY003880: Unable to find contextual data of type: javax.ws.rs.ext.Providers
    at org.jboss.resteasy.resteasy-jaxrs@3.7.0.Final//org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:77)
    at javax.ws.rs.api@1.0.2.Final//com.sun.proxy.$Proxy145.getMessageBodyReader(Unknown Source)
    at org.jboss.resteasy.resteasy-multipart-provider@3.7.0.Final//org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl$PartImpl.getBody(MultipartInputImpl.java:336)
    at org.jboss.resteasy.resteasy-multipart-provider@3.7.0.Final//org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl$PartImpl.getBodyAsString(MultipartInputImpl.java:392)

看起来,当调用ContextParameterInjector$GenericDelegatingProxy.invoke时,ResteasyProviderFactorycontextualData是空的。

如何解决这个问题?这是个窃听器吗?

有趣的是,如果我使客户端方法本身成为JAX-RS资源,并从另一个客户端请求它,一切都可以工作。contextualData人口稠密。

代码语言:javascript
运行
复制
@GET
@Path("get")
@Produces(MediaType.APPLICATION_JSON)
public void get()
{
  try (Response response = this.proxy.test();) {
    ...
    MultipartInput multipartInput = response.readEntity(MultipartInput.class);
    for (InputPart inputPart : multipartInput.getParts()) {
    try {
      MultipartRelatedInput relatedInput = inputPart.getBody(MultipartRelatedInput.class, null);
    } catch (IOException exception) {}
  }
}

但是,如果直接调用客户端方法,则仍然存在相同的问题。

环境为Windows10Pro1903,OpenJDK11U-JDKx64_ Windows _hotspot_11.0.4_11,WildFly 17.0.1,WildFly,RESTEasy 3.7.0.Final。

--我最近一次尝试来了解出了什么问题--揭示了它很可能是餐厅-多部分-供应商中的一个bug。目前,当从响应流读取多部分层次结构的第一级时,已注册的提供程序被缓存在MultipartInputImplMultipartInputImpl中。从响应流中读取MultipartInput之后,contextualData就消失了,但是在读取它们的身体时,注册的提供者仍然可以通过savedProviders为嵌套的PartImpl提供程序。问题是,在创建嵌套的savedProviders实例时,MultipartInput没有被填充到多部分层次结构的下一层。

--我现在的解决办法是在之前手动推送提供程序,并在使用pushContextpopContextData进行处理后弹出它们。

代码语言:javascript
运行
复制
public void get()
{
  try (Response response = this.proxy.test();) {
    ...
    MultipartInput multipartInput = response.readEntity(MultipartInput.class);
    for (InputPart inputPart : multipartInput.getParts()) {
    try {
      MultipartInput relatedInput = inputPart.getBody(MultipartInput.class, null);
      ResteasyProviderFactory.pushContext(Providers.class, ResteasyProviderFactory.getInstance());
      String json = relatedInput.getParts().get(0).getBodyAsString(); // does not fail anymore
      ResteasyProviderFactory.popContextData(Providers.class);
    } catch (IOException exception) {}
  }
}

我要开始一个问题。

EN

回答 1

Stack Overflow用户

发布于 2020-06-25 12:57:07

根据链接Framework.html,您可以看到引号

Resteasy将自动加载一组默认提供程序。(基本上所有META-INF/services/javax.ws.rs.ext.Providers文件中列出的所有类)。此外,您还可以通过方法调用Configuration提供的Client.configuration()对象手动注册其他提供程序、过滤器和拦截器。Configuration还允许您设置可能需要的各种配置属性。

因此,如果添加类名org.jboss.resteasy.plugins.providers.multipart.MultipartReader,那就足够了

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58751034

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档