文章目录

  • 1. 复现错误
  • 2. 分析错误
  • 3. 解决问题
  • 4. 文末总结

1. 复现错误

今天写完页面按钮排序接口,如下代码所示:

@ApiOperationSupport(author = "super先生", order = 8)
@ApiOperation(value = "页面按钮排序")
@PostMapping("/sort/pageButton")
public ReturnResult sortPageButton(
    @Validated @RequestBody SortPageButtonDto sortPageButtonDto,
    BindingResult bindingResult) {
  BindingParamUtil.checkParam(bindingResult);
  return appPageButtonService.sortPageButton(sortPageButtonDto);
}

使用postman测试时,却报出如下图错误:

全网详细解决Cannot deserialize instance of `com.xxx.实体类`out of START_ARRAY token at [Source: (PushbackInpu

此时,立即查看控制台报出的错误信息,如下代码所示:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `com.xxx.SortPageButtonDto` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.xxx.SortPageButtonDto` out of START_ARRAY token
 at [Source: (PushbackInputStream); line: 1, column: 1]
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:389)
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:342)
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:185)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at com.github.xiaoymin.knife4j.spring.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:87)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ......

由于错误信息较多,我们提取主要的错误信息,即Cannot deserialize instance of 'com.xxx.SortPageButtonDto' out of START_ARRAY token at [Source: (PushbackInputStream); line: 1, column: 1]

2. 分析错误

正赶上最近ChatGPT比较火,借助它来帮助我分析错误,如下图所示:

全网详细解决Cannot deserialize instance of `com.xxx.实体类`out of START_ARRAY token at [Source: (PushbackInpu

ChatGPT什么都没有返回,即无法理解我的问题,看来,只能通过我自己去排查错误了。

再次看错误信息Cannot deserialize instance of 'com.xxx.SortPageButtonDto' out of START_ARRAY token,将它简单地翻译成中文就是无法反序列化SortPageButtonDto类的实例。

为什么无法反序列化SortPageButtonDto类的实例呢?

首先,去排查SortPageButtonDto类,如下代码所示:

@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(description = "页面按钮排序请求类")
public class SortPageButtonDto {
  @Size(min = 1)
  @ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
  private List<SortPageButton> sortPageButtons;
  @ApiModel(description = "查询条件请求类")
  @Data
  public class SortPageButton {
    @NotNull(message = "id不能为空")
    @ApiModelProperty(name = "id", value = "页面按钮id", required = true, example = "1")
    private Long id;
    @NotNull(message = "排序值不能为空")
    @ApiModelProperty(name = "seq", value = "排序值", required = true, example = "1")
    private Long seq;
  }
}

SortPageButtonDto类是用来接收前端传的数组格式的参数,如下代码:

[
    {
        "id": 1,
        "seq": 20
    },
    {
        "id": 2,
        "seq": 21
    }
]

因而,我在SortPageButtonDto类中,又定义一个SortPageButton内部类。而SortPageButton类作为SortPageButtonDto类的属性,从而来接收前端传的数组。

这样写并没有问题,但却报出上面的错误,于是到处查找资料。

有资料说,上述json格式存在问题,需要修改成如下格式:

{
    "sortPageButtonDto": [
        {
            "id": 1,
            "seq": 20
        },
        {
            "id": 2,
            "seq": 21
        }
    ]
}

修改成如上格式后,再次使用postman调用页面按钮排序接口。虽然不报错了,但是后端接不到参数,也就是null值,如下图所示:

全网详细解决Cannot deserialize instance of `com.xxx.实体类`out of START_ARRAY token at [Source: (PushbackInpu

既然上述方法行不通,那就使用如下方法解决。

3. 解决问题

尝试修改SortPageButtonDto类,删除SortPageButton内部类,如下代码所示:

@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(description = "页面按钮排序请求类")
public class SortPageButtonDto {
  @NotNull(message = "id不能为空")
  @ApiModelProperty(name = "id", value = "页面按钮id", required = true, example = "1")
  private Long id;
  @NotNull(message = "排序值不能为空")
  @ApiModelProperty(name = "seq", value = "排序值", required = true, example = "1")
  private Long seq;
}

同时,修改上文起始/sort/pageButton的接口代码,如下所示:

@ApiOperationSupport(author = "super先生", order = 8)
@ApiOperation(value = "页面按钮排序")
@PostMapping("/sort/pageButton")
public ReturnResult sortPageButton(
    @Validated @RequestBody List<SortPageButtonDto> sortPageButtonDto,
    BindingResult bindingResult) {
  BindingParamUtil.checkParam(bindingResult);
  return appPageButtonService.sortPageButton(sortPageButtonDto);
}

全网详细解决Cannot deserialize instance of `com.xxx.实体类`out of START_ARRAY token at [Source: (PushbackInpu

此时,重新启动项目,并再次使用postman测试,仍旧报出同样的错误,如下图所示:

全网详细解决Cannot deserialize instance of `com.xxx.实体类`out of START_ARRAY token at [Source: (PushbackInpu

将上图中的json格式的请求参数,恢复成起始请求的json格式,再次向后端发送请求,如下图所示:

从上图可以清晰地看到,如上修改后,后端可成功地接收到前端传的数组参数。

经过反复尝试之后,终于解决了这个错误,如释重负般地关上电脑,下班回家。

4. 文末总结

出现这种错误,一般是后端使用集合或数组来接收前端的参数,如下代码所示:


//集合接参
@Size(min = 1)
@ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
private List<SortPageButton> sortPageButtons;
//数组接参
@Size(min = 1)
@ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
private SortPageButton[] sortPageButtons;

但由于传参不规范,导致Jackson解析数据时,无法拿到实际的参数值,从而报出上述的错误。

因而,在解决该错误时,前后端需要配合修改。不然后端修改了,前端没有修改,依然会报出上述错误。

发表回复