【问题标题】:Deserialize a json array to objects using Jackson and WebClient使用 Jackson 和 WebClient 将 json 数组反序列化为对象
【发布时间】:2018-07-13 20:56:36
【问题描述】:

我在使用 Spring 对 json 数组进行反序列化时遇到问题。 我有来自服务的这个 json 响应:

[
    {
        "symbol": "XRPETH",
        "orderId": 12122,
        "clientOrderId": "xxx",
        "price": "0.00000000",
        "origQty": "25.00000000",
        "executedQty": "25.00000000",
        "status": "FILLED",
        "timeInForce": "GTC",
        "type": "MARKET",
        "side": "BUY",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "time": 1514558190255,
        "isWorking": true
    },
    {
        "symbol": "XRPETH",
        "orderId": 1212,
        "clientOrderId": "xxx",
        "price": "0.00280000",
        "origQty": "24.00000000",
        "executedQty": "24.00000000",
        "status": "FILLED",
        "timeInForce": "GTC",
        "type": "LIMIT",
        "side": "SELL",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "time": 1514640491287,
        "isWorking": true
    },
    ....
]

我使用 Spring WebFlux 中的新 WebClient 获取此 json,代码如下:

@Override
    public Mono<AccountOrderList> getAccountOrders(String symbol) {
        return binanceServerTimeApi.getServerTime().flatMap(serverTime -> {
            String apiEndpoint = "/api/v3/allOrders?";
            String queryParams = "symbol=" +symbol.toUpperCase() + "&timestamp=" + serverTime.getServerTime();
            String signature = HmacSHA256Signer.sign(queryParams, secret);
            String payload = apiEndpoint + queryParams + "&signature="+signature;
            log.info("final endpoint:"+ payload);
            return this.webClient
                    .get()
                    .uri(payload)
                    .accept(MediaType.APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(AccountOrderList.class)
                    .log();
        });
    }

AccountOrderList

public class AccountOrderList {

    private List<AccountOrder> accountOrders;

    public AccountOrderList() {
    }

    public AccountOrderList(List<AccountOrder> accountOrders) {
        this.accountOrders = accountOrders;
    }

    public List<AccountOrder> getAccountOrders() {
        return accountOrders;
    }

    public void setAccountOrders(List<AccountOrder> accountOrders) {
        this.accountOrders = accountOrders;
    }
}

AccountOrder 是一个映射字段的简单 pojo。

实际上,当我点击 get 时,它会说:

org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize instance of `io.justin.demoreactive.domain.AccountOrder` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `io.justin.demoreactive.domain.AccountOrder` out of START_ARRAY token
 at [Source: UNKNOWN; line: -1, column: -1]

如何使用新的 webflux 模块正确反序列化 json?我究竟做错了什么?

2018 年 5 月 2 日更新

两个答案都是正确的。他们完美地解决了我的问题,但最后我决定使用稍微不同的方法:

@Override
    public Mono<List<AccountOrder>> getAccountOrders(String symbol) {
        return binanceServerTimeApi.getServerTime().flatMap(serverTime -> {
            String apiEndpoint = "/api/v3/allOrders?";
            String queryParams = "symbol=" +symbol.toUpperCase() + "&timestamp=" + serverTime.getServerTime();
            String signature = HmacSHA256Signer.sign(queryParams, secret);
            String payload = apiEndpoint + queryParams + "&signature="+signature;
            log.info("final endpoint:"+ payload);
            return this.webClient
                    .get()
                    .uri(payload)
                    .accept(MediaType.APPLICATION_JSON)
                    .retrieve()
                    .bodyToFlux(AccountOrder.class)
                    .collectList()
                    .log();
        });
    }

另一种方法是直接返回 A Flux,这样您就不必将其转换为列表。 (这就是通量:n 个元素的集合)。

【问题讨论】:

  • 您是创建上述响应还是从第 3 方获得此响应?
  • 这是来自第 3 方的回应。我无法更改回复@Ravi

标签: java spring spring-boot jackson spring-webflux


【解决方案1】:

要与AccountOrderList类匹配的响应,json必须是这样的

{
  "accountOrders": [
    {
        "symbol": "XRPETH",
        "orderId": 12122,
        "clientOrderId": "xxx",
        "price": "0.00000000",
        "origQty": "25.00000000",
        "executedQty": "25.00000000",
        "status": "FILLED",
        "timeInForce": "GTC",
        "type": "MARKET",
        "side": "BUY",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "time": 1514558190255,
        "isWorking": true
    },
    {
        "symbol": "XRPETH",
        "orderId": 1212,
        "clientOrderId": "xxx",
        "price": "0.00280000",
        "origQty": "24.00000000",
        "executedQty": "24.00000000",
        "status": "FILLED",
        "timeInForce": "GTC",
        "type": "LIMIT",
        "side": "SELL",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "time": 1514640491287,
        "isWorking": true
    },
    ....
]
}

这就是错误消息“out of START_ARRAY token”的内容

如果您无法更改响应,请更改您的代码以接受这样的数组

this.webClient.get().uri(payload).accept(MediaType.APPLICATION_JSON)
                        .retrieve().bodyToMono(AccountOrder[].class).log();

你可以把这个数组转换成List,然后返回。

【讨论】:

    【解决方案2】:

    您的回复只是List&lt;AccountOrder&gt;。但是,您的 POJO 已经包裹了 List&lt;AccountOrder&gt;。所以,根据你的 POJO,你的 JSON 应该是

    {
      "accountOrders": [
        {
    

    但是,你的 JSON

    [
        {
           "symbol": "XRPETH",
           "orderId": 12122,
            ....
    

    因此,存在不匹配且反序列化失败。您需要更改为

    bodyToMono(AccountOrder[].class)
    

    【讨论】:

      【解决方案3】:

      关于您对问题的更新答案,使用 bodyToFlux 不必要地效率低下,并且在语义上也没有多大意义,因为您并不真正想要订单流。您想要的只是能够将响应解析为列表。

      bodyToMono(List&lt;AccountOrder&gt;.class) 由于类型擦除而无法工作。您需要能够在运行时保留类型,Spring 为此提供了ParameterizedTypeReference

      bodyToMono(new ParameterizedTypeReference<List<AccountOrder>>() {})
      

      【讨论】:

      • 谢谢!我处于同样不稳定的情况下,端点的响应是一组项目对象。但是,我想问这个问题的扩展,有没有一种好方法可以将此响应映射到响应包装类?例如类似于 ` { "itemCount" : 10, "itemsList" : [ { item1 }, { item2 }, ... ] } `
      • 这是可能的,但您必须使用自定义反序列化器。我个人避免这样做,而是更喜欢通过在数据对象和域对象之间建立一个映射函数来明确转换。
      • 知道了,谢谢!我制作了不同的Response 类,并使用了地图步骤和Builder() 来构建新的响应!
      • 谢谢 .. 这有帮助
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-02
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多