简体   繁体   中英

How to get data from reactive WebClient response

I want to parse some data from stackexchange with reactive WebClient, but it throws an exception:

2021-02-03 23:55:17.544  INFO 16180 --- [           main] by.dzikovskiy.idt.Application            : Starting Application using Java 11.0.9.1 on DESKTOP-MT9VJGK with PID 16180 (C:\projects\WebCient\target\classes started by Vitaliy in C:\projects\WebCient)
2021-02-03 23:55:17.545  INFO 16180 --- [           main] by.dzikovskiy.idt.Application            : No active profile set, falling back to default profiles: default
2021-02-03 23:55:18.438  INFO 16180 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8081
2021-02-03 23:55:18.446  INFO 16180 --- [           main] by.dzikovskiy.idt.Application            : Started Application in 1.149 seconds (JVM running for 1.772)
Exception in thread "main" org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize instance of `by.dzikovskiy.idt.entity.ItemsData` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `by.dzikovskiy.idt.entity.ItemsData` out of START_ARRAY token
 at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 10] (through reference chain: by.dzikovskiy.idt.entity.StackResponse["items"])
    at org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:228)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ Body from GET https://api.stackexchange.com/2.2/answers?site=stackoverflow&page=1&pagesize=5&order=desc&sort=activity&filter=default [DefaultClientResponse]

I have such entity classes

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class StackResponse {
    private ItemsData items;
}

@JsonIgnoreProperties(ignoreUnknown = true)
@ToString
public class ItemsData {
    @JacksonXmlElementWrapper(useWrapping = false)
    List<Owner> owner;

    @JacksonXmlElementWrapper(useWrapping = false)
    public List<Owner> getOwner() {
        return owner;
    }

    public void setOwner(List<Owner> owner) {
        this.owner = owner;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonTypeName("owner")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
public class Owner {
    @JsonProperty("user_id")
    private long userId;
    @JsonProperty("display_name")
    private String displayName;
    private String link;

}

WebClient that makes a request

@Component
public class StackResponseClient {

    private final WebClient webClient;

    @Autowired
    public StackResponseClient(WebClient webClient) {
        this.webClient = webClient;
    }

    public Mono<StackResponse> getOwners() {
        return this.webClient
                .get()
                .uri("https://api.stackexchange.com/2.2/answers?site=stackoverflow&page=1&pagesize=5&order=desc&sort=activity&filter=default")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(StackResponse.class);
    }

}

And main

@SpringBootApplication
public class Application {


    public static void main(String[] args) throws JsonProcessingException {
        SpringApplication.run(Application.class, args);

        ApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);

        // code for testing json mapper
//         ObjectMapper objectMapper = new ObjectMapper();
//        StackResponse stackResponse = new StackResponse();
//        ItemsData itemsData = new ItemsData();
//        itemsData.setOwner(List.of(
//                new Owner(1,"one","link1"),
//                new Owner(2,"two","link2"),
//                new Owner(3,"three","link3")
//                ));
//        stackResponse.setItems(itemsData);
//        System.out.println(objectMapper.writeValueAsString(stackResponse));

        StackResponseClient stackResponseClient = ctx.getBean(StackResponseClient.class);

        StackResponse stackResponse = stackResponseClient.getOwners().block();
        System.out.println(stackResponse);
    }

}

Also I tested how jackson ser/deserialize my classes and its have different json structure than response from stackexchange. And maybe that the problem.

{
    "items": {
        "owner": [
            {
                "owner": {
                    "link": "link1",
                    "user_id": 1,
                    "display_name": "one"
                }
            },
            {
                "owner": {
                    "link": "link2",
                    "user_id": 2,
                    "display_name": "two"
                }
            },
            {
                "owner": {
                    "link": "link3",
                    "user_id": 3,
                    "display_name": "three"
                }
            }
        ]
    }
}

Question

What I need to change to get StackResponse object or at least list like List<Owner> in main?

Thank you

The response that you want to deserialize i believe has this structure

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Response {
    private List<Item> items;
}

Items.class

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Item {
    private Owner owner;
}

Owner.class

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Owner {
    private int reputation;
    private int user_id;
    private String link;
    private String display_name;
    
    // etc. etc.

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM