java.lang.IllegalArgumentException at java.sql.Date.getHours

myskies發表於2019-01-19

錯誤描述:
springboot中,使用進行net.sf.json.JSONObject.fromObject(javaObject)進行json序列化時,得到錯誤Caused by:java.lang.IllegalArgumentException at java.sql.Date.getHours(Date.java:187)

最終解決方案:自定義轉換器,並注入至轉換方法。

我們解決問題的順序如下:

  1. 翻譯
  2. 依據翻譯和現實情況,嘗試解決問題。
  3. 看官方文件,或是方法描述,嘗試解決問題。
  4. 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.Datejson序列化方法。

在相關資料的學習中,並沒有找到統一配置的路徑。但是可以在轉換前,定義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找到關鍵點,然後再結合關鍵點來學習特定的官方文件,最後達到解決問題並且能夠理解自己所解決問題的根本原因的目的。

相關文章