天天看点

异常解决篇:Spring Boot默认错误返回格式变成数组@RequestBody无法解析Json格式

前言

记录下在使用spring boot时,不小心将jackson的全局配置覆盖导致的,正常的json格式无法解析的问题。

ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
           

就是由于上面的配置,配置项应用于全局生效导致的。下面我们看下具体情况。

问题还原

controller方法
@Slf4j
@RestController
@RequestMapping
public class UserClientService {

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping("users")
    public User addUser(@RequestBody User user) {
        return user;
    }
}
           
调用截图
异常解决篇:Spring Boot默认错误返回格式变成数组@RequestBody无法解析Json格式

错误信息

[
    "java.util.LinkedHashMap",
    {
        "timestamp": [
            "java.util.Date",
            
        ],
        "status": ,
        "error": "Bad Request",
        "exception": "org.springframework.http.converter.HttpMessageNotReadableException",
        "message": "JSON parse error: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class com.zm.zhuma.user.model.po.User; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class com.zm.zhuma.user.model.po.User\n at [Source: [email protected]; line: 1, column: 1]",
        "path": "/zhuma-user2/users"
    }
]
           

备注

1. 我们可以看到controller的方法和调用时传入的json参数格式并没有错误,但是却返回了JSON parse error问题,粗略的翻译下就是 不期待object对象,期待传递的是一个array数组。

2. 还有一个异常现象就是,spring boot默认的错误返回并不是一个json的对象格式,而是一个数组这里进行一下说明,spring boot的默认异常时返回结果是靠{@link org.springframework.boot.autoconfigure.web.DefaultErrorAttributes}类,使用的对象是LinkedHashMap。不做处理时,返回的默认错误结果应该是下面这样:

{
    "timestamp": ,
    "status": ,
    "error": "Not Found",
    "message": "No message available",
    "path": "/zhuma-user2/users/error-path"
}
           

Bug解决方案

最终排查到是项目中配置ObjectMapper的时候修改成了全局配置,导致影响到了spring mvcjson格式解析(因为spring mvc默认就是使用jackson做json处理的)

@Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(Include.NON_NULL);
        //设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //将类名称序列化到json串中
        //mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        return mapper;
    }
           

分析

我们先来分析下enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)这个配置,配置该项后,json格式序列化时会将对象类名称信息也会序列化进来,反序列化时同样也是需要 类和值的信息,格式是一个数组(两个长度),数组[0]存储类的信息,数组[1]存储值信息,这也印证了为什么我们错误提示是 Unexpected token (START_OBJECT), expected START_ARRAY。

所以去掉改配置,就是我们最常用的json格式了。O(∩_∩)O~

继续阅读