commons.beanutils轉換Date類型值為null的字段時報錯,ConversionException: No value specified for 'Date'


錯誤發生:用戶自定義了一個將Map轉成指定Bean類的轉換器,繼承自org.springframework.beans.BeanUtils ,如下

    public static <T> T convertMap(Map<String, Object> sources, Class<T> type)
            throws IllegalAccessException, InvocationTargetException {    
        T bean = BeanUtils.instantiate(type);
        org.apache.commons.beanutils.BeanUtils.populate(bean, sources);
        return bean;
    }

錯誤信息:

Caused by: org.apache.commons.beanutils.ConversionException: No value specified for 'Date'       at org.apache.commons.beanutils.converters.AbstractConverter.handleMissing(AbstractConverter.java:310)

    at org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:136)

    at org.apache.commons.beanutils.converters.ConverterFacade.convert(ConverterFacade.java:60)

    at org.apache.commons.beanutils.BeanUtilsBean.convert(BeanUtilsBean.java:1078)

    at org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:1011)

    at org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:830)

    at org.apache.commons.beanutils.BeanUtils.populate(BeanUtils.java:433)

跟蹤發現錯誤發生在hannleMissing處理空值的函數中。

關鍵代碼:

 
public abstract class AbstractConverter implements Converter {
.................................此處省略代碼....................................................
protected Object handleMissing(Class type) {

        if (useDefault || type.equals(String.class)) {
            Object value = getDefault(type);
            if (useDefault && value != null && !(type.equals(value.getClass()))) {
                try {
                    value = convertToType(type, defaultValue);
                } catch (Throwable t) {
                    log().error("    Default conversion to " + toString(type)
                            + "failed: " + t);
                }
            }
            if (log().isDebugEnabled()) {
                log().debug("    Using default "
                        + (value == null ? "" : toString(value.getClass()) + " ")
                        + "value '" + defaultValue + "'");
            }
            return value;
        }

       ConversionException cex =  new ConversionException("No value specified for '" +
                toString(type) + "'");
        if (log().isDebugEnabled()) {
            log().debug("    Throwing ConversionException: " + cex.getMessage());
            log().debug("    " + DEFAULT_CONFIG_MSG);
        }
        throw cex;

    }

    protected void setDefaultValue(Object defaultValue) {
        useDefault = false;
        if (log().isDebugEnabled()) {
            log().debug("Setting default value: " + defaultValue);
        }
        if (defaultValue == null) {
           this.defaultValue  = null;
        } else {
           this.defaultValue  = convert(getDefaultType(), defaultValue);
        }
        useDefault = true;
    }

.....................此處省略代碼.......................................
}

上面代碼紅色部分是具體報錯位置,綠色部分是用 new XXConverter(null或defaultval) 注冊默認值后執行這個函數,后面對空值的數據轉換可以設置為注冊時的默認值。

報錯原因:本項目中Date轉換器沒有注冊到默認值。

 public ConvertUtilsBean() {
        converters.setFast(false);   
        deregister();
        converters.setFast(true);
    }
 public void deregister() {

        converters.clear();
        
        registerPrimitives(false);
        registerStandard(false, false);
        registerOther(true);
        registerArrays(false, 0);
        register(BigDecimal.class, new BigDecimalConverter());
        register(BigInteger.class, new BigIntegerConverter());
    }
...........................................此處省略部分代碼....................................................
    private void registerOther(boolean throwException) {
        register(Class.class,         throwException ? new ClassConverter()        : new ClassConverter(null));
        register(java.util.Date.class, throwException ? new DateConverter()      : new DateConverter(null));
        register(Calendar.class,      throwException ? new CalendarConverter()     : new CalendarConverter(null));
        register(File.class,          throwException ? new FileConverter()         : new FileConverter(null));
        register(java.sql.Date.class, throwException ? new SqlDateConverter()      : new SqlDateConverter(null));
        register(java.sql.Time.class, throwException ? new SqlTimeConverter()      : new SqlTimeConverter(null));
        register(Timestamp.class,     throwException ? new SqlTimestampConverter() : new SqlTimestampConverter(null));
        register(URL.class,           throwException ? new URLConverter()          : new URLConverter(null));
    }

 

項目啟動后用的deregister函數初始化部分非原始數據類型的轉換器,Date類型轉換器注冊用的是 new DateConverter() ,未設置默認值(上面代碼綠色部分)。因此在實際轉換日期字段時,由於Date轉換器沒有設置默認值,useDefault為false,if條件沒有進入設值,然后就執行下面的拋出錯誤了。

解決方法:

方法一:如果Date類型沒必要設為null,在調用轉換器前就設置對應的日期數據,這個治標不治本。

方法二:可以自定義轉換器的類中設置Date轉換器null對應的默認值。不同類型的轉換器默認值設置,可以參考ConvertUtilsBean類等,如 private Double defaultDouble = new Double(0.0); 還有相關方法 deregister -> registerPrimitives ,一般DoubleConverter轉換器會講null值默認轉換為0.0。轉換器默認值的設置以項目需要為主,數值型類的可以自定義為null或對應的0值。

    static {
        ConvertUtils.register(new LongConverter(null), Long.class);
        ConvertUtils.register(new ShortConverter(null), Short.class);
        ConvertUtils.register(new IntegerConverter(null), Integer.class);
        ConvertUtils.register(new DoubleConverter(null), Double.class);
        ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
        ConvertUtils.register(new DateConverter(null), Date.class);
    }

 注:數值類型轉換器父類NumberConverter轉換方法toNumber(Class sourceType, Class targetType, Number value)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM