可以参考《SpringMVC接口测试异常:Can not deserialize instance
2016-01-22 10:53
555 查看
之前使用springmvc搭建了restful风格的接口服务,在使用mockmvc进行集成测试的时候出现了异常:Can not deserialize instance of int out of START_OBJECT token。为什么会出现这个问题?怎么解决这个问题呢?接下来本文详细分析讲解这个问题。
测试代码
执行上述测试代码控制台异常错误
POST请求中content的值必须为json格式(存储形式可以是字符串,也可以是byte数组);
被@RequestBody注解的参数类型必须是完全可以接收参数值的类型,比如:Map,JSONObject,或者对应的JavaBean;
@RequestBody将post请求中content值转为一个整体对象,该对象包含所有参数名和参数值,所以接口方法必须也是一个参数完全接收所有参数名和参数值。根据上面展示的代码来看,@RequestBody将params对象json形式内容转换成一个整体参数值,无论是p1还是p2,都无法接收该参数值。
测试响应结果正常:
表单式提交
参数形式:p1=v1&p2=v2,服务端接口方法获取参数可以采用@RequestParam注解对应参数方式。
客户端提交
这里的客户端具体指自定义编码的客户端。将所有参数信息组织成一个整体对象,然后转换成json对象,设置为post请求content的值,提交到服务端。此时服务端接口方法获取参数即需要采用本文讨论的方式。其实本文method1方法也可以自定义一个包含p1和p2两个字段的JavaBean类型,自己可以尝试一下,呵呵!
文章作者:
xiaohui249
本文链接:
http://javatech.wang/index.php/archives/82/
版本所有 ©转载时必须以链接形式注明作者和原始出处
一、问题展现
接口代码@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; }
测试代码
@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()); }
执行上述测试代码控制台异常错误
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
二、分析问题
我们先从接口方法中参数注解@RequestBody说起吧!我们大家都知道@ResponseBody是把接口方法返回结果转化成JSON形式提供给方法调用者,那么相对应的,@RequestBody是把客户端POST请求content部分转化成JavaBean对象或者JSON对象。@RequestBody的解析有两个条件:POST请求中content的值必须为json格式(存储形式可以是字符串,也可以是byte数组);
被@RequestBody注解的参数类型必须是完全可以接收参数值的类型,比如:Map,JSONObject,或者对应的JavaBean;
@RequestBody将post请求中content值转为一个整体对象,该对象包含所有参数名和参数值,所以接口方法必须也是一个参数完全接收所有参数名和参数值。根据上面展示的代码来看,@RequestBody将params对象json形式内容转换成一个整体参数值,无论是p1还是p2,都无法接收该参数值。
三、解决问题
在method1方法中定义一个可以接收整体参数值的对象类型即可,通常可选类型有:Map、JSONObject和JavaBean,JSONObject相对于Map,其取值方法更灵活。下面我们将在method1方法中定义一个JSONObject类型的参数。@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; }
测试响应结果正常:
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 = []
四、扩展
对POST接口的请求可以采取表单式和接口客户端式两种方法提交。表单式提交
参数形式:p1=v1&p2=v2,服务端接口方法获取参数可以采用@RequestParam注解对应参数方式。
客户端提交
这里的客户端具体指自定义编码的客户端。将所有参数信息组织成一个整体对象,然后转换成json对象,设置为post请求content的值,提交到服务端。此时服务端接口方法获取参数即需要采用本文讨论的方式。其实本文method1方法也可以自定义一个包含p1和p2两个字段的JavaBean类型,自己可以尝试一下,呵呵!
文章作者:
xiaohui249
本文链接:
http://javatech.wang/index.php/archives/82/
版本所有 ©转载时必须以链接形式注明作者和原始出处
相关文章推荐
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- Spring整合Quartz(JobDetailBean方式)
- Spring整合Quartz(JobDetailBean方式)
- 模拟Spring的简单实现
- spring+html5实现安全传输随机数字密码键盘
- Spring中属性注入详解
- SpringMVC框架下JQuery传递并解析Json格式的数据是如何实现的
- struts2 spring整合fieldError问题
- spring的jdbctemplate的crud的基类dao
- 读取spring配置文件的方法(spring读取资源文件)
- Spring Bean基本管理实例详解
- java实现简单美女拼图游戏
- 详解Java的Spring框架中的事务管理方式
- 解析Java的Spring框架的BeanPostProcessor发布处理器
- Java开发框架spring实现自定义缓存标签
- java基本教程之线程休眠 java多线程教程
- JSP开发中在spring mvc项目中实现登录账号单浏览器登录
- spring boot实战之内嵌容器tomcat配置