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

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

在使用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)
@ResponseBody
public 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;
}

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


现象

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


把自定义类换成Java自带的封装类都能够正确运行;

当程序正常运行时,map是空的(不是null)。而异常程序的map包含两个值,一个是GStation对象的值,一个是org.springframework.validation.BindingResult.GStation=org.springframework.validation.BeanPropertyBindingResult: 0 errors。

 有图为证:


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



image.png

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

image.png

 因此做出大胆假设,出错的原因是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)就行了。


解决办法

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


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


@RequestMapping(value = "/updStation", method = POST)
@ResponseBody
public 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;
}

不需要Spring帮忙创建map,自己new一个。


@RequestMapping(value = "/updStation", method = POST)
@ResponseBody
public 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数据,所以报出异常。


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


目录
相关文章
|
6月前
|
Web App开发 前端开发 JavaScript
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
345 0
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
|
4月前
|
定位技术
vue-baidu-map 报错 | map is undefined
vue-baidu-map 报错 | map is undefined
78 1
|
4月前
|
定位技术
vue-baidu-map 报错 | BMap is undefined
vue-baidu-map 报错 | BMap is undefined
127 1
|
4月前
echarts 报错 —— Component series.map not exists. Load it first
echarts 报错 —— Component series.map not exists. Load it first
133 0
|
6月前
|
运维 API 开发工具
对象存储oss使用问题之获取临时访问凭证报错:It is not a map value.如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
469 0
|
Dubbo Java 应用服务中间件
再谈序列化之rpc调用失败和jackson序列化时不允许Map中的key为null
再谈序列化之rpc调用失败和jackson序列化时不允许Map中的key为null
237 0
|
C++
C++ std::map报错的解决办法:_Rb_tree_increment(std::_Rb_tree_node_base const
C++ std::map报错的解决办法:_Rb_tree_increment(std::_Rb_tree_node_base const
1207 0
|
前端开发 Java Spring
Spring MVC报错: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'XXXController' method
Spring MVC报错: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'XXXController' method
254 0
Spring MVC报错: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'XXXController' method
|
Go 索引
Golang语言(打卡✏️第三天)map、递归、报错和练习题|Go主题月
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。 Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
187 0
|
Java
MessagePack Java Jackson Dataformat 在 Map 中不使用 String 为 Key 的序列化
当你希望在 Map 中不使用 String 为 Key,那么你需要使用 MessagePackKeySerializer 来为 key 进行序列化。 本测试方法,可以在 https://github.com/cwiki-us-demo/serialize-deserialize-demo-java/blob/master/src/test/java/com/insight/demo/serialize/MessagePackSerializer.java 中找到。
879 0