4

错误描述:
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找到关键点,然后再结合关键点来学习特定的官方文档,最后达到解决问题并且能够理解自己所解决问题的根本原因的目的。


潘杰
3.1k 声望239 粉丝