2014年1月23日

BeanUtilsBean 的小小應用 2

在利用 BeanUtilsBean 的一點小技巧來解決部份 property 不做 copyProperties() 的需要之後。
如果處理 BigDecimal 的 property 賦值, 而其值為 null 時, 會出現...
Exception in thread "main" org.apache.commons.beanutils.ConversionException: No value specified
at org.apache.commons.beanutils.converters.BigDecimalConverter.convert(BigDecimalConverter.java:...)
...


解決問題前, 先從 BeanUtils 取得 BeanUtilsBean.getInstance() 來處理 copyProperties() 的 source 中看到:

    private static final ContextClassLoaderLocal beansByClassLoader = new ContextClassLoaderLocal() {

        protected Object initialValue() {
            return new BeanUtilsBean();
        }
    };

實際是使用了預設的 BeanUtilsBean() constructor:

    public BeanUtilsBean() {
        this(new ConvertUtilsBean(), new PropertyUtilsBean());
    }

    public BeanUtilsBean(ConvertUtilsBean convertUtilsBean, PropertyUtilsBean propertyUtilsBean) {
        this.log = LogFactory.getLog(BeanUtils.class);
        this.convertUtilsBean = convertUtilsBean;
        this.propertyUtilsBean = propertyUtilsBean;
    }
明顯的看到它使用了預設的 ConvertUtilsBean() constructor, 並在 deregister() method 中建構各類型的 converter 以便爾後的 properties 賦值處理:

    public ConvertUtilsBean() {
        this.converters.setFast(false);
        deregister();
        this.converters.setFast(true);
    }
    ...
    public void deregister() {
        ...
        register(BigDecimal.class, new BigDecimalConverter());
        ...
    }
    ...
但, 當中 BigDecimalConverter() constructor 是不預設賦值的:
    public BigDecimalConverter() {
        this.defaultValue = null;
        this.useDefault = false;
    }
另一 constructor 則是:
    public BigDecimalConverter(Object defaultValue) {
        this.defaultValue = defaultValue;
        this.useDefault = true;
    }
也就是說, 可以使用另一組 BigDecimalConverter() constructor 來避免上述的 exception 發生:
    BeanUtilsBean defaultNullValueBeanUtils = new BeanUtilsBean(new ConvertUtilsBean() {

        @Override
        public void deregister() {
            super.deregister();
            // 這裡還是預設了 null 為其值
            register(new org.apache.commons.beanutils.converters.BigDecimalConverter(null), BigDecimal.class);
            ...
        }
    }, new PropertyUtilsBean());
    ...
    defaultNullValueBeanUtils.copyProperties(dest, orig);
    ...
done!

沒有留言: