【问题标题】:Extract specific node of JSON response in RESTEasy Client在 RESTEasy 客户端中提取 JSON 响应的特定节点
【发布时间】:2017-01-16 07:15:09
【问题描述】:

我正在使用 RESTEasy 客户端从 API 检索 JSON 字符串。 JSON 有效负载如下所示:

{
  "foo1" : "",
  "foo2" : "",
  "_bar" : {
    "items" : [
      { "id" : 1 , "name" : "foo", "foo" : "bar" },
      { "id" : 2 , "name" : "foo", "foo" : "bar" },
      { "id" : 3 , "name" : "foo", "foo" : "bar" },
      { "id" : 4 , "name" : "foo", "foo" : "bar" }
    ]
  }
}

现在我只想提取items 节点用于对象映射。拦截 JSON 响应正文并将其修改为将 items 作为根节点的最佳方法是什么?

我将RESTEasy proxy framework 用于我的 API 方法。

REST 客户端代码:

ResteasyWebTarget target = client.target("https://"+server);
target.request(MediaType.APPLICATION_JSON);
client.register(new ClientAuthHeaderRequestFilter(getAccessToken()));
MyProxyAPI api = target.proxy(MyProxyAPI.class);
MyDevice[] result = api.getMyDevice();

RESTEasy 代理接口:

public interface MyProxyAPI {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/device")
    public MyDevice[] getMyDevices();

    ...
}

【问题讨论】:

  • 转换为 Javascript 对象并将其作为 Object 检索。
  • items 是根重要还是您不想映射消息的任何其他元素?快速浏览 RestEasy 文档,您正在通过 JAXB 提供程序对 Java bean 使用自动编组/解组?
  • @dbreaux 是的,我只是不想映射任何其他元素。有关简化的实现代码,请参阅我对 OP 的编辑。我当然可以注册一个提供者来更改消息正文,但我想知道这样的提供者的实现会是什么样子。
  • 当映射自动完成时,为什么要增加预处理响应的复杂性而不是事后简单地提取对象?
  • 我认为,我需要在 java 中对完整的 Json 结构进行建模,我认为这很混乱。实际上,我的“项目”节点周围还有更多的对象。

标签: java jakarta-ee jax-rs resteasy jackson2


【解决方案1】:

我同样希望不必为包含比我关心的更多字段的消息定义复杂的 Java 类。在我的 JEE 服务器 (WebSphere) 中,Jackson 是底层 JSON 实现,这似乎是 RESTEasy 的一个选项。 Jackson 有一个 @JsonIgnoreProperties 注释,可以忽略未知的 JSON 字段:

import javax.xml.bind.annotation.XmlType;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@XmlType
@JsonIgnoreProperties(ignoreUnknown = true)
public class JsonBase {}

我不知道其他 JSON 实现是否有类似的功能,但它确实看起来很自然。

(我还写了一个 blog post 与这个和一些其他与我的 WebSphere 环境相关的 JAX-RS 技术。)

【讨论】:

  • 这是一个不错的解决方案,但它可能不适用于 OP 描述的情况。 items 节点是 _bar 的子节点,而不是根节点的子节点。
  • 您仍然可以通过定义其中几乎没有任何内容的包装类来做到这一点。就我而言,这比其他选择要好。
【解决方案2】:

您可以创建一个ReaderInterceptor 并使用 Jackson 来操作您的 JSON:

public class CustomReaderInterceptor implements ReaderInterceptor {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) 
                      throws IOException, WebApplicationException {

        JsonNode tree = mapper.readTree(context.getInputStream());
        JsonNode items = tree.get("_bar").get("items");
        context.setInputStream(new ByteArrayInputStream(mapper.writeValueAsBytes(items)));
        return context.proceed();
    }
}

然后将上面创建的ReaderInterceptor注册到你的Client

Client client = ClientBuilder.newClient();
client.register(CustomReaderInterceptor.class);

【讨论】:

  • 实际上,您对另一个问题的回答也可能是一个简单的解决方案:stackoverflow.com/a/38352932/796761
  • 您通过 dbreaux 链接的旧解决方案(获取 JSON 并通过杰克逊树访问所需的节点)是我迄今为止作为解决方法所做的。这当然不适用于代理框架。我会尝试拦截器。谢谢。
  • @MartinPeter 当然!试试看,让我知道它是否适合你:)
猜你喜欢
  • 2018-03-19
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 2015-11-14
  • 2017-01-19
  • 1970-01-01
  • 2016-03-06
  • 2019-09-25
相关资源
最近更新 更多