錯誤描述:
在springboot
中,使用進行net.sf.json.JSONObject.fromObject(javaObject)
進行json
序列化時,得到錯誤Caused by:java.lang.IllegalArgumentException at java.sql.Date.getHours(Date.java:187)
。
最終解決方案:自定義轉換器,並注入至轉換方法。
我們解決問題的順序如下:
- 翻譯
- 依據翻譯和現實情況,嘗試解決問題。
- 看官方文件,或是方法描述,嘗試解決問題。
-
google
相關關鍵字,解決問題。
翻譯
由以下異常引起:在java.sql.Date.getHours
方法上(該方法位於Data.java的187行
)發生了java.lang.IllegalArgumentException
異常。
其中:Illegal
:非法的, Argument
:論據
現實情況
現實情況是我們並沒有主動呼叫這個getHour()
方法,所以猜想,應該是net.sf.json.JSONObject.fromObject(javaObject)
進行json
序列化時,主動呼叫了該方法。
通過打斷點的方式,我們在fromObject(javaObject)
本行A、下一行B、java.sql.Date.getHours
的187行C,分別打一個斷點,最終發現執行順序為:A->C->異常。符合我們的猜想預期。
如果是A->B->C->異常,則說明並不是由A觸發的C,也就證明我們的猜想是錯誤的。你可以參與下文來快速的找到執行過程。
原因找到了,但無論是net.sf.json.JSONObject.fromObject(javaObject)
還是java.sql.Date.getHours
,都不是我們自已維護的。所以得到結論:兩者在進行配合時發生了衝突,當前解決方法則只能棄用一方,或是向一方注入配置,來繞過java.sql.Date.getHours
方法的呼叫。
看方法描述
我們找到java.sql.Date.getHours()
方法:
/**
* This method is deprecated and should not be used because SQL Date
* values do not have a time component.
*
* @deprecated
* @exception java.lang.IllegalArgumentException if this method is invoked
* @see #setHours
*/
@Deprecated
public int getHours() {
throw new java.lang.IllegalArgumentException();
}
基本的意思就是說,這個方法已經棄用了,因為:sql.Date
只是精確到日
,根本就沒有hour
這說,所以你想得到小時,這當然不行了。原來問題出在net.sf.json.JSONObject.fromObject(javaObject)
上,當其轉換sql.Date
時,呼叫了不該呼叫已棄的getHour()
方法,所以觸發了這個異常。
結論:好像誰都沒有錯。第一個的原則是:只要你有getXXX()
我就呼叫,保證對所有的get
方法全部序列化。第二個的原則是:雖然我歷史上有過getHour()
方法,但是這個方法根本就不應該被呼叫,我的最小精確度是天
,你問我是幾小時,我哪知道,所以你呼叫我,我就報出異常。
按我們以往的經驗,一些牛氣的第三方庫,是會給使用者提供一些重寫的介面的介面的,比如我們在專案啟動時,向net.sf.json
的特定介面,注入一個Bean
,該Bean
的作用是:重寫sql.Date
的json
序列化方法。
在相關資料的學習中,並沒有找到統一配置的路徑。但是可以在轉換前,定義JsonConfig
,並將自定義的轉換器裝配進行。但我認為每次都這樣新建一個轉換器,太麻煩了。所以後面,又嘗試了一些其它的方法,最後,沒有辦法,其它的方法都是曲線救國,最終還是繞到了定義轉換器的路上來了。
實際開發中,我還嘗試使用排除@Deprecated
的方法,該方法會得到一個其它的我們不想得到的結果,不再詳細闡述;已嘗試了將sql.Date換成util.Date,雖然能夠序列化,但序列化後的內容並不是我們想要的,進行請求資料繫結時,會得到400錯誤,不在闡述
使用轉換器前:
JSONObject jsonObject = JSONObject.fromObject(mandatoryInstrument);
使用轉換器後:
jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonValueProcessor() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd");
@Override
public Object processArrayValue(Object o, JsonConfig jsonConfig) {
return simpleDateFormat.format(o);
}
@Override
public Object processObjectValue(String s, Object o, JsonConfig jsonConfig) {
if (o != null) {
return simpleDateFormat.format(o);
} else {
return null;
}
}
});
JSONObject jsonObject = JSONObject.fromObject(mandatoryInstrument, jsonConfig);
結論
在學習一門新技術的時候或是新的問題的時候,上來直接看官方文件是不現實的,需要結合google
找到關鍵點,然後再結合關鍵點來學習特定的官方文件,最後達到解決問題並且能夠理解自己所解決問題的根本原因的目的。