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();
});
}
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() + "×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();
});
}
これに代わる方法として、A Fluxを直接返すことで、リストに変換する必要がなくなります。 (それがフラックスです:n要素のコレクション)。
レスポンスを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
},
....
]
}
これは、エラーメッセージに "START_ARRAYトークンが不足しています"と表示されています。
応答を変更できない場合は、このように配列を受け入れるようにコードを変更してください
this.webClient.get().uri(payload).accept(MediaType.APPLICATION_JSON)
.retrieve().bodyToMono(AccountOrder[].class).log();
この配列をリストに変換してから返すことができます。
あなたの応答は単に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>>() {})