天天看點

enum的json反序列化問題 415 Unsupported Media Type

enum的反序列化問題 415 Unsupported Media Type

當你的程式線上上出現了error code 415,而本地環境正常的時候,可能就是由于enum的反序列化導緻的。

當在enum的反序列化工廠方法上添加了@JsonCreator,且該方法有多個參數,每個參數前都加了@JsonProperty注解,但沒有在JsonProperty中顯式的指定value為參數名時,就會導緻這一問題。

這是一個神奇的bug,在本地測試的時候,不管是用postman還是前端頁面發送參數,後端的controller都可以正常的接收,将json的字元串,反序列化為實體類。但是一到了線上,就顯示415 content type not supported

{

    "timestamp": "2021-08-13T07:29:27.173+0000",

    "status": 415,

    "error": "Unsupported Media Type",

    "message": "Content type 'application/json;charset=UTF-8' not supported",

    "path": "/ops/submit_inventory_evaluate"

}

經檢查restcontroller requestmapping requestbody注解都放在了合适位置,且前端js裡content type也采用了application/json,或postman在header裡content type也是如此設定。最初懷疑為前端的問題,反複檢查無誤後,通過postman測試,發現還是415錯誤,之後将問題定位到了後端。

因為本地環境正常,導緻測試很困難,隻能一點點的排查,發到線上環境再測試,最終将問題鎖定到了實體類中一個enum屬性。在加了@JsonIgnore注解後,線上環境就可以正常的反序列化了,在檢視enum中的toEnum方法時,注意到了上面的@JsonCreator注解,仔細閱讀jackson2.9.0中關于該注解的說明。發現該注解當作用于有多個參數的構造或工廠方法上時,每個參數都需要加@JsonProperty,同時在該注解中需要顯式的指定value的值,對應哪個屬性。除非你使用了支援檢測參數名稱的擴充子產品,因為JDK8之前,預設 JDK 版本無法從位元組碼中存儲或檢索參數名稱。

通過這段話,我開始猜測是本地Oracle的JDK和線上JDK的差別,但是都是JDK8應該都支援這一特性。後面通過搜尋這一特性——反射擷取方法的參數名稱,發現除了要求JDK8及以上,還有一點是編譯的時候必須指定編譯選項:-parameters,來打開這一特性的支援,預設是關閉的狀态。

打開這一特性有三種方法:

  1. 手動指令方式編譯:javac -parameters XXX.java
  1. IDE(以Idea為例)編譯:Settings -> Build,Execution,Deployment -> Compiler -> Java Compiler
  • Additional command line parameters框中設定為-parameters
  • Override compiler parameters per-module中新增一個module并設定 Compilation options值為-parameters
  • enum的json反序列化問題 415 Unsupported Media Type
  1. Maven編譯:通過編譯插件指定,保證項目遷移的正确性(推薦)

其中第二種方法是IDEA,預設開啟的,通過删除這一參數設定,測試發現本地也出現了415錯誤,最終确認了問題的來源。