Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize a json array to objects using Jackson and WebClient

I have a problem during the deserialization of a json array using Spring. I have this json response from a service:

[     {         "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     },     .... ] 

I get this json using the new WebClient from Spring WebFlux, here the code:

@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 is a simple pojo that maps the fields.

Actually, when I hit a get it says:

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] 

How can I deserialize the json properly using the new webflux module? What am I doing wrong?

UPDATE 05/02/2018

Both answers are correct. They addressed perfectly my question but at the end I decided to use a slightly different approach:

@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();         });     } 

An alternative to this could be to return directly A Flux so you don't have to convert it to a list. (that's what flux are: a collection of n elements).

like image 937
Justin Avatar asked Feb 03 '18 14:02

Justin


People also ask

How do I pass a JSON object in WebClient?

WebClient client = WebClient. of(); // Send a serialized JSON object with "applicaiton/json" HttpResponse response = client. postJson("/items", new MyItem()); HttpResponse response = client. putJson("/items", new MyItem()); HttpResponse response = client.

How do I get JSON response from WebClient?

You would just use bodyToMono which would return a Mono object. WebClient webClient = WebClient. create(); String responseJson = webClient. get() .

How do I get data from mono WebClient?

Mono is a reactive publisher, that can emit 0 zero or 1 elements. Thus, in order to retrieve a single JSON resource with WebClient, we should use Mono publisher. We will use WebClient to read a JSON object and parse it into POJO. Example of WebClient reading single JSON Object as a POJO with Mono.


1 Answers

Regarding your updated answer to your question, using bodyToFlux is unnecessarily inefficient and semantically doesn't make much sense either as you don't really want a stream of orders. What you want is simply to be able to parse the response as a list.

bodyToMono(List<AccountOrder>.class) won't work due to type erasure. You need to be able to retain the type at runtime, and Spring provides ParameterizedTypeReference for that:

bodyToMono(new ParameterizedTypeReference<List<AccountOrder>>() {}) 
like image 122
Pin Avatar answered Sep 20 '22 14:09

Pin