nl.strohalm.cyclos.utils.binding.CustomBeanUtilsBean.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.utils.binding.CustomBeanUtilsBean.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.utils.binding;

import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.MappedPropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;

/**
 * Customized bean utils in order to check if a mapped property refers to an array or single value
 * @author luis
 */
public class CustomBeanUtilsBean extends BeanUtilsBean {
    @Override
    public void setProperty(final Object bean, String name, final Object value)
            throws IllegalAccessException, InvocationTargetException {

        // Resolve any nested expression to get the actual target bean
        Object target = bean;
        final int delim = findLastNestedIndex(name);
        if (delim >= 0) {
            try {
                target = getPropertyUtils().getProperty(bean, name.substring(0, delim));
            } catch (final NoSuchMethodException e) {
                return; // Skip this property setter
            }
            name = name.substring(delim + 1);
        }

        // Declare local variables we will require
        String propName = null; // Simple name of target property
        Class<?> type = null; // Java type of target property
        int index = -1; // Indexed subscript value (if any)
        String key = null; // Mapped key value (if any)

        // Calculate the property name, index, and key values
        propName = name;
        final int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
        if (i >= 0) {
            final int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
            try {
                index = Integer.parseInt(propName.substring(i + 1, k));
            } catch (final NumberFormatException e) {
                // Ignore
            }
            propName = propName.substring(0, i);
        }
        final int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
        if (j >= 0) {
            final int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
            try {
                key = propName.substring(j + 1, k);
            } catch (final IndexOutOfBoundsException e) {
                // Ignore
            }
            propName = propName.substring(0, j);
        }

        // Calculate the property type
        if (target instanceof DynaBean) {
            final DynaClass dynaClass = ((DynaBean) target).getDynaClass();
            final DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
            if (dynaProperty == null) {
                return; // Skip this property setter
            }
            type = dynaProperty.getType();
            if (type.isArray() || Collection.class.isAssignableFrom(type)) {
                type = Object[].class;
            }
        } else {
            PropertyDescriptor descriptor = null;
            try {
                descriptor = getPropertyUtils().getPropertyDescriptor(target, name);
                if (descriptor == null) {
                    return; // Skip this property setter
                }
            } catch (final NoSuchMethodException e) {
                return; // Skip this property setter
            }
            if (descriptor instanceof MappedPropertyDescriptor) {
                if (((MappedPropertyDescriptor) descriptor).getMappedWriteMethod() == null) {
                    return; // Read-only, skip this property setter
                }
                type = ((MappedPropertyDescriptor) descriptor).getMappedPropertyType();

                /**
                 * Overriden behaviour ------------------- When a type is Object on a mapped property, retrieve the value to check if it's an array
                 */
                if (Object.class.equals(type)) {
                    try {
                        final Object retrieved = getPropertyUtils().getMappedProperty(target, propName, key);
                        if (retrieved != null) {
                            final Class<?> retrievedType = retrieved.getClass();
                            if (retrievedType.isArray() || Collection.class.isAssignableFrom(retrievedType)) {
                                type = Object[].class;
                            }
                        }
                    } catch (final NoSuchMethodException e) {
                        throw new PropertyException(target, propName + "(" + key + ")");
                    }
                }
            } else if (descriptor instanceof IndexedPropertyDescriptor) {
                if (((IndexedPropertyDescriptor) descriptor).getIndexedWriteMethod() == null) {
                    return; // Read-only, skip this property setter
                }
                type = ((IndexedPropertyDescriptor) descriptor).getIndexedPropertyType();
            } else {
                if (descriptor.getWriteMethod() == null) {
                    return; // Read-only, skip this property setter
                }
                type = descriptor.getPropertyType();
            }
        }

        /**
         * Overriden behaviour ------------------- When a type is Map on a mapped property, retrieve the value to check if it's an array
         */
        if (Map.class.isAssignableFrom(type) && StringUtils.isNotEmpty(key)) {
            try {
                final Map<?, ?> map = (Map<?, ?>) getPropertyUtils().getProperty(target, propName);
                final Object retrieved = map.get(key);
                if (retrieved != null) {
                    final Class<?> retrievedType = retrieved.getClass();
                    if (retrievedType.isArray() || Collection.class.isAssignableFrom(retrievedType)) {
                        type = Object[].class;
                    }
                }
            } catch (final NoSuchMethodException e) {
                throw new PropertyException(target, propName + "(" + key + ")");
            }
        }

        // Convert the specified value to the required type
        Object newValue = null;
        if (type.isArray() && (index < 0)) { // Scalar value into array
            if (value == null) {
                final String values[] = new String[1];
                values[0] = (String) value;
                newValue = getConvertUtils().convert(values, type);
            } else if (value instanceof String) {
                final String values[] = new String[1];
                values[0] = (String) value;
                newValue = getConvertUtils().convert(values, type);
            } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert((String[]) value, type);
            } else {
                newValue = value;
            }
        } else if (type.isArray()) { // Indexed value into array
            if (value instanceof String) {
                newValue = getConvertUtils().convert((String) value, type.getComponentType());
            } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert(((String[]) value)[0], type.getComponentType());
            } else {
                newValue = value;
            }
        } else { // Value into scalar
            if ((value instanceof String) || (value == null)) {
                newValue = getConvertUtils().convert((String) value, type);
            } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert(((String[]) value)[0], type);
            } else if (getConvertUtils().lookup(value.getClass()) != null) {
                newValue = getConvertUtils().convert(value.toString(), type);
            } else {
                newValue = value;
            }
        }

        // Invoke the setter method
        try {
            if (index >= 0) {
                getPropertyUtils().setIndexedProperty(target, propName, index, newValue);
            } else if (key != null) {
                getPropertyUtils().setMappedProperty(target, propName, key, newValue);
            } else {
                getPropertyUtils().setProperty(target, propName, newValue);
            }
        } catch (final NoSuchMethodException e) {
            throw new InvocationTargetException(e, "Cannot set " + propName);
        }

    }

    private int findLastNestedIndex(final String expression) {
        // walk back from the end to the start
        // and find the first index that
        int bracketCount = 0;
        for (int i = expression.length() - 1; i >= 0; i--) {
            final char at = expression.charAt(i);
            switch (at) {
            case PropertyUtils.NESTED_DELIM:
                if (bracketCount < 1) {
                    return i;
                }
                break;

            case PropertyUtils.MAPPED_DELIM:
            case PropertyUtils.INDEXED_DELIM:
                // not bothered which
                --bracketCount;
                break;

            case PropertyUtils.MAPPED_DELIM2:
            case PropertyUtils.INDEXED_DELIM2:
                // not bothered which
                ++bracketCount;
                break;
            }
        }
        // can't find any
        return -1;
    }

}