programing

Jackson 및 WebClient를 사용하여 json 어레이를 개체로 역직렬화

elseif 2023. 3. 10. 21:16

Jackson 및 WebClient를 사용하여 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();
        });
    }

Account Order List(계정 주문 목록)

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;
    }
}

Account Order는 필드를 매핑하는 단순한 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월 02일

둘 다 정답입니다.그들은 내 질문을 완벽하게 해결했지만, 결국 나는 약간 다른 접근법을 사용하기로 결정했다.

@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개의 원소의 집합입니다).

질문에 대한 업데이트된 답변에 대해bodyToFlux불필요하게 비효율적이고 의미론적으로도 의미가 없습니다.주문 스트림을 원하지 않기 때문입니다.필요한 것은 단순히 응답을 목록으로 해석할 수 있는 것입니다.

bodyToMono(List<AccountOrder>.class)는 타입 삭제로 동작하지 않습니다.실행 시 유형을 유지할 수 있어야 하며 스프링은ParameterizedTypeReference그 경우:

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

응답을 일치시키려면AccountOrderListclass, 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 토큰"이라고 표시됩니다.

응답을 변경할 수 없는 경우 다음과 같이 어레이를 받아들이도록 코드를 변경합니다.

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)

언급URL : https://stackoverflow.com/questions/48598233/deserialize-a-json-array-to-objects-using-jackson-and-webclient