nl.strohalm.cyclos.utils.conversion.CoercionHelper.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.utils.conversion.CoercionHelper.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.conversion;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Locale;

import nl.strohalm.cyclos.entities.Entity;
import nl.strohalm.cyclos.utils.ClassHelper;
import nl.strohalm.cyclos.utils.EntityHelper;
import nl.strohalm.cyclos.utils.IntValuedEnum;
import nl.strohalm.cyclos.utils.StringValuedEnum;

import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang.ClassUtils;

/**
 * Class used to convert from a data type to another
 * @author luis
 */
public class CoercionHelper {

    /**
     * Converts the given value to the given type, using heuristics. The supported types are: primitives, arrays, Number, String, Boolean, Character,
     * Calendar, Date, Enum, Entity, Locale and Collection
     */
    @SuppressWarnings("unchecked")
    public static <T> T coerce(final Class<T> toType, final Object value) {
        try {
            return (T) convert(toType, value);
        } catch (final ConversionException e) {
            throw e;
        } catch (final Exception e) {
            throw new ConversionException("Cannot convert " + value + " to " + toType.getName(), e);
        }
    }

    /**
     * Converts an object to a collection of the given type, using the given element type
     * @return The resulting collection - it may be empty, but never null
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> Collection<T> coerceCollection(final Class<T> elementType,
            final Class<? extends Collection> collectionType, final Object value) {
        final Collection<T> collection = ClassHelper
                .instantiate(collectionType == null ? ArrayList.class : collectionType);
        final Iterator<?> iterator = IteratorUtils.getIterator(value);
        while (iterator.hasNext()) {
            collection.add(coerce(elementType, iterator.next()));
        }
        return collection;
    }

    /**
     * Converts an object to a collection with the given element type.
     * @return The resulting collection - it may be empty, but never null
     */
    public static <T> Collection<T> coerceCollection(final Class<T> elementType, final Object value) {
        return coerceCollection(elementType, null, value);
    }

    /**
     * Returns the first array item, or null if an empty array
     */
    public static <T> T first(final T[] array) {
        if (array == null || array.length == 0) {
            return null;
        }
        return array[0];
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static Object convert(Class toType, Object value) {
        if ("".equals(value)) {
            value = null;
        }
        // If we do not want a collection, but the value is one, use the first value
        if (value != null && !(Collection.class.isAssignableFrom(toType) || toType.isArray())
                && (value.getClass().isArray() || value instanceof Collection)) {
            final Iterator it = IteratorUtils.getIterator(value);
            if (!it.hasNext()) {
                value = null;
            } else {
                value = it.next();
            }
        }

        // Check for null values
        if (value == null) {
            if (toType.isPrimitive()) {
                // On primitives, use the default value
                if (toType == Boolean.TYPE) {
                    value = Boolean.FALSE;
                } else if (toType == Character.TYPE) {
                    value = '\0';
                } else {
                    value = 0;
                }
            } else {
                // For objects, return null
                return null;
            }
        }

        // Check if the value is already of the expected type
        if (toType.isInstance(value)) {
            return value;
        }

        // If the class is primitive, use the wrapper, so we have an easier work of testing instances
        if (toType.isPrimitive()) {
            toType = ClassUtils.primitiveToWrapper(toType);
        }

        // Convert to well-known types
        if (String.class.isAssignableFrom(toType)) {
            if (value instanceof Entity) {
                final Long entityId = ((Entity) value).getId();
                return entityId == null ? null : entityId.toString();
            }
            return value.toString();
        } else if (Number.class.isAssignableFrom(toType)) {
            if (!(value instanceof Number)) {
                if (value instanceof String) {
                    value = new BigDecimal((String) value);
                } else if (value instanceof Date) {
                    value = ((Date) value).getTime();
                } else if (value instanceof Calendar) {
                    value = ((Calendar) value).getTimeInMillis();
                } else if (value instanceof Entity) {
                    value = ((Entity) value).getId();
                    if (value == null) {
                        return null;
                    }
                } else {
                    throw new ConversionException("Invalid number: " + value);
                }
            }
            final Number number = (Number) value;
            if (Byte.class.isAssignableFrom(toType)) {
                return number.byteValue();
            } else if (Short.class.isAssignableFrom(toType)) {
                return number.shortValue();
            } else if (Integer.class.isAssignableFrom(toType)) {
                return number.intValue();
            } else if (Long.class.isAssignableFrom(toType)) {
                return number.longValue();
            } else if (Float.class.isAssignableFrom(toType)) {
                return number.floatValue();
            } else if (Double.class.isAssignableFrom(toType)) {
                return number.doubleValue();
            } else if (BigInteger.class.isAssignableFrom(toType)) {
                return new BigInteger(number.toString());
            } else if (BigDecimal.class.isAssignableFrom(toType)) {
                return new BigDecimal(number.toString());
            }
        } else if (Boolean.class.isAssignableFrom(toType)) {
            if (value instanceof Number) {
                return ((Number) value).intValue() != 0;
            } else if ("on".equalsIgnoreCase(value.toString())) {
                return true;
            } else {
                return Boolean.parseBoolean(value.toString());
            }
        } else if (Character.class.isAssignableFrom(toType)) {
            final String str = value.toString();
            return (str.length() == 0) ? null : str.charAt(0);
        } else if (Calendar.class.isAssignableFrom(toType)) {
            if (value instanceof Date) {
                final Calendar cal = new GregorianCalendar();
                cal.setTime((Date) value);
                return cal;
            }
        } else if (Date.class.isAssignableFrom(toType)) {
            if (value instanceof Calendar) {
                final long millis = ((Calendar) value).getTimeInMillis();
                try {
                    return ConstructorUtils.invokeConstructor(toType, millis);
                } catch (final Exception e) {
                    throw new IllegalStateException(e);
                }
            }
        } else if (Enum.class.isAssignableFrom(toType)) {
            Object ret;
            try {
                ret = Enum.valueOf(toType, value.toString());
            } catch (final Exception e) {
                ret = null;
            }
            if (ret == null) {
                Object[] possible;
                try {
                    possible = (Object[]) toType.getMethod("values").invoke(null);
                } catch (final Exception e) {
                    throw new IllegalStateException(
                            "Couldn't invoke the 'values' method for enum " + toType.getName());
                }
                if (StringValuedEnum.class.isAssignableFrom(toType)) {
                    final String test = coerce(String.class, value);
                    for (final Object item : possible) {
                        if (((StringValuedEnum) item).getValue().equals(test)) {
                            ret = item;
                            break;
                        }
                    }
                } else if (IntValuedEnum.class.isAssignableFrom(toType)) {
                    final int test = coerce(Integer.TYPE, value);
                    for (final Object item : possible) {
                        if (((IntValuedEnum) item).getValue() == test) {
                            ret = item;
                            break;
                        }
                    }
                } else {
                    throw new ConversionException("Invalid enum: " + value);
                }
            }
            return ret;
        } else if (Entity.class.isAssignableFrom(toType)) {
            final Long id = coerce(Long.class, value);
            return EntityHelper.reference(toType, id);
        } else if (Locale.class.isAssignableFrom(toType)) {
            return LocaleConverter.instance().valueOf(value.toString());
        } else if (Collection.class.isAssignableFrom(toType)) {
            final Collection collection = (Collection) ClassHelper.instantiate(toType);
            final Iterator iterator = IteratorUtils.getIterator(value);
            while (iterator.hasNext()) {
                collection.add(iterator.next());
            }
            return collection;
        } else if (toType.isArray()) {
            final Collection collection = coerceCollection(toType.getComponentType(), value);
            final Object[] array = (Object[]) Array.newInstance(toType.getComponentType(), collection.size());
            return collection.toArray(array);
        }

        // We don't know how to convert the value
        throw new ConversionException("Cannot coerce value to: " + toType.getName());
    }
}