使用 Jackson 和 WebClient 将 json 数组反序列化为对象
Deserialize a json array to objects using Jackson and WebClient
我在使用 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() + "×tamp=" + 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();
});
}
账户订单列表
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?我究竟做错了什么?
更新 05/02/2018
两个答案都正确。他们完美地解决了我的问题,但最后我决定使用稍微不同的方法:
@Override
public Mono<List<AccountOrder>> getAccountOrders(String symbol) {
return binanceServerTimeApi.getServerTime().flatMap(serverTime -> {
String apiEndpoint = "/api/v3/allOrders?";
String queryParams = "symbol=" +symbol.toUpperCase() + "×tamp=" + 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();
});
}
另一种方法是 return 直接使用 A Flux,这样您就不必将其转换为列表。 (这就是通量:n 个元素的集合)。
要与 AccountOrderList
class 匹配的响应,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,然后 return。
您的回复很简单 List<AccountOrder>
。但是,您的 POJO 已包装 List<AccountOrder>
。所以,根据你的 POJO,你的 JSON
应该是
{
"accountOrders": [
{
但是,你的JSON
是
[
{
"symbol": "XRPETH",
"orderId": 12122,
....
因此,存在不匹配且反序列化失败。您需要更改为
bodyToMono(AccountOrder[].class)
关于您对问题的更新答案,使用 bodyToFlux
不必要地低效,而且在语义上也没有多大意义,因为您真的不想要订单流。您想要的只是能够将响应解析为列表。
由于类型擦除,bodyToMono(List<AccountOrder>.class)
将不起作用。您需要能够在运行时保留类型,Spring 为此提供了 ParameterizedTypeReference
:
bodyToMono(new ParameterizedTypeReference<List<AccountOrder>>() {})
我在使用 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() + "×tamp=" + 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();
});
}
账户订单列表
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?我究竟做错了什么?
更新 05/02/2018
两个答案都正确。他们完美地解决了我的问题,但最后我决定使用稍微不同的方法:
@Override
public Mono<List<AccountOrder>> getAccountOrders(String symbol) {
return binanceServerTimeApi.getServerTime().flatMap(serverTime -> {
String apiEndpoint = "/api/v3/allOrders?";
String queryParams = "symbol=" +symbol.toUpperCase() + "×tamp=" + 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();
});
}
另一种方法是 return 直接使用 A Flux,这样您就不必将其转换为列表。 (这就是通量:n 个元素的集合)。
要与 AccountOrderList
class 匹配的响应,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,然后 return。
您的回复很简单 List<AccountOrder>
。但是,您的 POJO 已包装 List<AccountOrder>
。所以,根据你的 POJO,你的 JSON
应该是
{
"accountOrders": [
{
但是,你的JSON
是
[
{
"symbol": "XRPETH",
"orderId": 12122,
....
因此,存在不匹配且反序列化失败。您需要更改为
bodyToMono(AccountOrder[].class)
关于您对问题的更新答案,使用 bodyToFlux
不必要地低效,而且在语义上也没有多大意义,因为您真的不想要订单流。您想要的只是能够将响应解析为列表。
bodyToMono(List<AccountOrder>.class)
将不起作用。您需要能够在运行时保留类型,Spring 为此提供了 ParameterizedTypeReference
:
bodyToMono(new ParameterizedTypeReference<List<AccountOrder>>() {})