Jackson报错org.codehaus.jackson.map.JsonMappingException

来源:互联网 发布:java创建pdf文件 编辑:程序博客网 时间:2024/04/25 12:28

  在使用Spring MVC + Jackson-1.9.12时报的一个异常,本文暂时也只是描述一下如何绕开这个异常,并简单说明一下出错原因。希望如果有大神碰巧看过这个问题,不吝赐教。

异常详细描述

主要是Jackson的异常:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.validation.support.BindingAwareModelMap["org.springframework.validation.BindingResult.GStation"]->org.springframework.validation.BeanPropertyBindingResult["messageCodesResolver"]); nested exception is org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.validation.support.BindingAwareModelMap["org.springframework.validation.BindingResult.GStation"]->org.springframework.validation.BeanPropertyBindingResult["messageCodesResolver"])org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:194)org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:179)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.writeWithMessageConverters(AnnotationMethodHandlerAdapter.java:1037)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.handleResponseBody(AnnotationMethodHandlerAdapter.java:995)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(AnnotationMethodHandlerAdapter.java:944)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:441)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)javax.servlet.http.HttpServlet.service(HttpServlet.java:710)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)javax.servlet.http.HttpServlet.service(HttpServlet.java:803)org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

因为使用Spring MVC框架控制器处理请求,所以同时会报Spring的异常:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.validation.support.BindingAwareModelMap["org.springframework.validation.BindingResult.GStation"]->org.springframework.validation.BeanPropertyBindingResult["messageCodesResolver"])org.codehaus.jackson.map.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:52)org.codehaus.jackson.map.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:25)org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)org.codehaus.jackson.map.ser.std.MapSerializer.serializeFields(MapSerializer.java:262)org.codehaus.jackson.map.ser.std.MapSerializer.serialize(MapSerializer.java:186)org.codehaus.jackson.map.ser.std.MapSerializer.serialize(MapSerializer.java:23)org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610)org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1613)org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:191)org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:179)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.writeWithMessageConverters(AnnotationMethodHandlerAdapter.java:1037)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.handleResponseBody(AnnotationMethodHandlerAdapter.java:995)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(AnnotationMethodHandlerAdapter.java:944)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:441)org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)javax.servlet.http.HttpServlet.service(HttpServlet.java:710)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)javax.servlet.http.HttpServlet.service(HttpServlet.java:803)org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

代码

  前台代码使用jQuery的ajax异步调用,代码中利用Spring MVC可以直接将data数据赋值到pojo对象属性中。

$.ajax({    type : "post",    url : "/businesssite/updStation",    data : station,    dataType : "json",    success : function(data) {        if(data && data.msg == "s") {            alert("成功");        } else {            alert("失败");        }    },    error : function(e) {        alert("错误:" + e.responseText);    }});

  后台代码Spring MVC的注解定义控制器请求路径及参数,station为需要获取ajax参数的对象,map为需要返回的对象(此处的map默认情况下会是Spring定义的BindingAwareModelMap的实例,Map、Model、ModelMap都是一样的。但由于Model接口没有clear方法,会影响其中一种处理bug的方法,下面会讲到。)

@RequestMapping(value = "/updStation", method = POST)@ResponseBodypublic Map<String, Object> updStation(GStation station, Map<String, Object> map) {    try {        log.debug(station);        map.put("msg", "s");    } catch (Exception e) {        log.error(e.getMessage(), e);        map.put("msg", "e");    }    return map;}

此时就会报出本文开头提到的异常。

现象

  通过打断点,查看进入控制器的方法中各个对象实例的状态,发现正常程序与异常程序之间的区别:

  1. 把自定义类换成Java自带的封装类都能够正确运行;
  2. 当程序正常运行时,map是空的(不是null)。而异常程序的map包含两个值,一个是GStation对象的值,一个是org.springframework.validation.BindingResult.GStation=org.springframework.validation.BeanPropertyBindingResult: 0 errors。

  有图为证:

         1. 出现异常的代码中map或model的值

         2. 未出现异常的代码中map或model的值


  因此做出大胆假设,出错的原因是ajax传递多值至对象中时,Spring MVC会在map里面增加两个值(一个是传输的数据对象,一个是对于对象属性绑定的验证结果),而这两个值是Jackson将map处理成json格式时出错 。通过Spring文档中的内容也验证了这一说法,内容如下:

Command or form objects to bind request parameters to bean properties (via setters) or directly to fields, with customizable type conversion, depending on@InitBinder methods and/or the HandlerAdapter configuration. See thewebBindingInitializer property on RequestMappingHandlerAdapter. Such command objects along with their validation results will be exposed as model attributes by default, using the command class class name - e.g. model attribute "orderAddress" for a command object of type "some.package.OrderAddress". The ModelAttribute annotation can be used on a method argument to customize the model attribute name used.

所以,只要map是空的(非null)就行了。

解决办法

  既然找到了解决思路,那方法就有多种了:

  1. 通过map.clear()方法将map清空(此方法适用于Map及MedalMap);

    @RequestMapping(value = "/updStation", method = POST)@ResponseBodypublic Map<String, Object> updStation(GStation station, Map<String, Object> map) {    map.clear();    try {        log.debug(station);        map.put("msg", "s");    } catch (Exception e) {        log.error(e.getMessage(), e);        map.put("msg", "e");    }    return map;}
  2. 不需要Spring帮忙创建map,自己new一个。

    @RequestMapping(value = "/updStation", method = POST)@ResponseBodypublic Map<String, Object> updStation(GStation station) {    Map<String, Object> map = new HashMap<String, Object>();    try {        log.debug(station);        map.put("msg", "s");    } catch (Exception e) {        log.error(e.getMessage(), e);        map.put("msg", "e");    }    return map;}

注:Spring MVC帮助定义的对象是BindingAwareModelMap,通过源码或API可以知道,这个类是LinkedHashMap的子类,也算是HashMap的子类,所以这的地方创建HashMap对象不算错。

后语

  这个异常开始的时候感觉是Jackson的异常,但是起因似乎还是Spring MVC。在Map中多出的数据是Spring MVC对于向对象中赋值时增加的校验信息,当这些校验信息提交给Jackson时,Jackson无法将其转换成json数据,所以报出异常。

  如果有大神路过,跪求指正。

0 0
原创粉丝点击