JSON映射DTO时报Cannot deserialize instance of out of START_ARRAY token如何解决
报错原因
这个错误是Jackson反序列化时类型不匹配导致的:你配置的反序列化目标是PersonDto对象(对应JSON结构{...}),但Jackson实际解析时拿到的是数组开头的START_ARRAY令牌(对应JSON结构[...]),触发原因是PersonDto上的@JsonRootName注解配置和反序列化逻辑不匹配。
你当前的JSON结构外层是对象,内部data字段才是人员数组,而PersonDto本身已经定义了List<PersonDetail> data字段和JSON结构完全匹配,额外加的@JsonRootName(value = "data")注解是多余的:如果你的Jackson全局配置开了DeserializationFeature.UNWRAP_ROOT_VALUE,反序列化时会直接剥离外层JSON对象,取data字段对应的数组内容直接映射到PersonDto,自然会抛出数组转对象的类型不匹配错误。
修复方案
方案1(推荐,改动最小)
直接删除PersonDto类上的@JsonRootName(value = "data")注解即可,无需修改其他代码。
修改后的PersonDto示例:
@Builder(toBuilder = true) @NoArgsConstructor @AllArgsConstructor @Data @JsonIgnoreProperties(ignoreUnknown = true) public class PersonDto { List<PersonDetail> data = Lists.newArrayList(); @Builder(toBuilder = true) @NoArgsConstructor @AllArgsConstructor @Data public static class PersonDetail { @JsonProperty("firstname") private String firstname; @JsonProperty("lastname") private String lastName; @JsonProperty("email") private String email; } }
调用接口时仍然传入PersonDto.class作为响应类型参数,即可正常完成反序列化。
方案2(保留根节点解析配置)
如果你确实需要开启UNWRAP_ROOT_VALUE全局配置,可以删除PersonDto包装类,直接将响应类型指定为List<PersonDto.PersonDetail>,但需要修改你的post方法支持泛型类型解析:
- 新增支持
ParameterizedTypeReference的重载方法:
public <T, K> Mono<T> post(ParameterizedTypeReference<T> respType, K reqDto, Function<UriBuilder, URI> pathFunction, String token) { return webClient .post() .uri(pathFunction) .body(BodyInserters.fromValue(reqDto)) .header(HttpHeaders.AUTHORIZATION, BEARER + token) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON) .acceptCharset(StandardCharsets.UTF_8) .exchange() .flatMap(clientResponse -> { if (clientResponse.statusCode().is2xxSuccessful()) return clientResponse.bodyToMono(respType); return clientResponse.createException().flatMap(Mono::error); }); }
- 调用时传入泛型类型即可:
post(new ParameterizedTypeReference<List<PersonDto.PersonDetail>>() {}, reqDto, pathFunc, token)
内容的提问来源于stack exchange,提问作者bittersour
相关产品推荐
相关产品推荐

