天天看點

異常解決篇: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~

繼續閱讀