如何从响应式 WebClient 响应中获取数据
How to get data from reactive WebClient response
我想用响应式 WebClient 解析来自 stackexchange 的一些数据,但它抛出异常:
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=Whosebug&page=1&pagesize=5&order=desc&sort=activity&filter=default [DefaultClientResponse]
我有这样的实体类
@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
@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=Whosebug&page=1&pagesize=5&order=desc&sort=activity&filter=default")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(StackResponse.class);
}
}
和主要
@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);
}
}
我还测试了 jackson ser/deserialize 我的 类 和它的 json 结构与来自 stackexchange 的响应有何不同。也许这就是问题所在。
{
"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"
}
}
]
}
}
问题
我需要更改什么才能在 main 中获得 StackResponse
对象或至少像 List<Owner>
这样的列表?
谢谢
我相信你想要反序列化的响应具有这种结构
@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.
}
我想用响应式 WebClient 解析来自 stackexchange 的一些数据,但它抛出异常:
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=Whosebug&page=1&pagesize=5&order=desc&sort=activity&filter=default [DefaultClientResponse]
我有这样的实体类
@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
@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=Whosebug&page=1&pagesize=5&order=desc&sort=activity&filter=default")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(StackResponse.class);
}
}
和主要
@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);
}
}
我还测试了 jackson ser/deserialize 我的 类 和它的 json 结构与来自 stackexchange 的响应有何不同。也许这就是问题所在。
{
"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"
}
}
]
}
}
问题
我需要更改什么才能在 main 中获得 StackResponse
对象或至少像 List<Owner>
这样的列表?
谢谢
我相信你想要反序列化的响应具有这种结构
@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.
}