记录下在使用spring boot时,不小心将jackson的全局配置覆盖导致的,正常的json格式无法解析的问题。
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
就是由于上面的配置,配置项应用于全局生效导致的。下面我们看下具体情况。
@Slf4j
@RestController
@RequestMapping
public class UserClientService {
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("users")
public User addUser(@RequestBody User user) {
return user;
}
}
错误信息
[
"java.util.LinkedHashMap",
{
"timestamp": [
"java.util.Date",
1520232987376
],
"status": 400,
"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: java.io.PushbackInputStream@14ed86e2; 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": 1520236497590,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/zhuma-user2/users/error-path"
}
最终排查到是项目中配置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~