SpringMVC接口测试异常:Can not deserialize instance

以前使用springmvc搭建了restful风格的接口服务,在使用mockmvc进行集成测试的时候出现了异常:Can not deserialize instance of int out of START_OBJECT token。为何会出现这个问题?怎么解决这个问题呢?接下来本文详细分析讲解这个问题。 php

1、问题展示

  1. 接口代码
@ResponseBody
@RequestMapping(value = "/m1", method = RequestMethod.POST)
@ApiOperation(value = "测试方法1", httpMethod = "POST", response = ApiResult.class, notes = "测试方法1")
public ApiResult method1(@ApiParam(required = true, name = "p1", value = "参数1") @RequestBody String p1,
                            @ApiParam(required = true, name = "p2", value = "参数2") @RequestBody Integer p2) throws Exception {

    String content = "p1=" + p1 + ", p2=" + p2;
    System.out.println(content);

    ApiResult<String> result = new ApiResult<String>();
    result.setCode(ResultCode.SUCCESS.getCode());
    result.setData(content);
    return result;
}
  1. 测试代码
@Test
public void method1Test() throws Exception {
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("p1", "x001");
    params.put("p2", 10010);

    ObjectMapper mapper = new ObjectMapper();
    byte[] content = mapper.writeValueAsBytes(params);
    this.mockMvc.perform(post("/activation/m1").contentType(APPLICATION_JSON_UTF8).content(content).accept(APPLICATION_JSON_UTF8))
            .andExpect(status().isOk())
            .andExpect(content().contentType(APPLICATION_JSON_UTF8))
            .andExpect(jsonPath("$.code").value(2000))
            .andDo(print());

}
  1. 执行上述测试代码控制台异常错误
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of int out of START_OBJECT token at [Source: org.springframework.mock.web.DelegatingServletInputStream@3e0fa1; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:762)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:419)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:289)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:271)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2221)
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:168)
... 50 more

2、分析问题

  咱们先从接口方法中参数注解@RequestBody提及吧!咱们你们都知道@ResponseBody是把接口方法返回结果转化成JSON形式提供给方法调用者,那么相对应的,@RequestBody是把客户端POST请求content部分转化成JavaBean对象或者JSON对象。@RequestBody的解析有两个条件: java

  1. POST请求中content的值必须为json格式(存储形式能够是字符串,也能够是byte数组);
  2. 被@RequestBody注解的参数类型必须是彻底能够接收参数值的类型,好比:Map,JSONObject,或者对应的JavaBean;

  @RequestBody将post请求中content值转为一个总体对象,该对象包含全部参数名和参数值,因此接口方法必须也是一个参数彻底接收全部参数名和参数值。根据上面展现的代码来看,@RequestBody将params对象json形式内容转换成一个总体参数值,不管是p1仍是p2,都没法接收该参数值。 web

3、解决问题

  在method1方法中定义一个能够接收总体参数值的对象类型便可,一般可选类型有:Map、JSONObject和JavaBean,JSONObject相对于Map,其取值方法更灵活。下面咱们将在method1方法中定义一个JSONObject类型的参数。 spring

@ResponseBody
@RequestMapping(value = "/m1", method = RequestMethod.POST)
@ApiOperation(value = "测试方法1", httpMethod = "POST", response = ApiResult.class, notes = "测试方法1")
public ApiResult method1(@ApiParam(required = true, name = "p", value = "参数") @RequestBody JSONObject p) throws Exception {

    String content = "p1=" + p.getString("p1") + ", p2=" + p.getInt("p2");
    System.out.println(content);

    ApiResult<String> result = new ApiResult<String>();
    result.setCode(ResultCode.SUCCESS.getCode());
    result.setData(content);
    return result;
}

  测试响应结果正常: json

MockHttpServletResponse:
          Status = 200
   Error message = null
         Headers = {Content-Type=[application/json;charset=UTF-8]}
    Content type = application/json;charset=UTF-8
            Body = {"code":2000,"message":"","data":"p1=x001, p2=10010"}
   Forwarded URL = null
  Redirected URL = null
         Cookies = []

4、扩展

  对POST接口的请求能够采起表单式和接口客户端式两种方法提交。 数组

  1. 表单式提交
      参数形式:p1=v1&p2=v2,服务端接口方法获取参数能够采用@RequestParam注解对应参数方式。 restful

  2. 客户端提交
      这里的客户端具体指自定义编码的客户端。将全部参数信息组织成一个总体对象,而后转换成json对象,设置为post请求content的值,提交到服务端。此时服务端接口方法获取参数即须要采用本文讨论的方式。其实本文method1方法也能够自定义一个包含p1和p2两个字段的JavaBean类型,本身能够尝试一下,呵呵! mvc

文章做者: xiaohui249
本文连接: http://javatech.wang/index.php/archives/82/ 版本全部 ©转载时必须以连接形式注明做者和原始出处
相关文章
相关标签/搜索