net.sourceforge.jaulp.lang.ObjectUtils.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.jaulp.lang.ObjectUtils.java

Source

/**
 * Copyright (C) 2007 Asterios Raptis
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.sourceforge.jaulp.lang;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sourceforge.jaulp.io.ChangedAttributeResult;
import net.sourceforge.jaulp.io.SerializedObjectUtils;
import net.sourceforge.jaulp.reflection.ReflectionUtils;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;

/**
 * The Class ObjectUtils provides methods to clone, copy and compare objects. It also provides
 * methods to find changed data between Objects.
 */
public final class ObjectUtils {

    /** The Constant logger. */
    private static final Logger logger = Logger.getLogger(ObjectUtils.class.getName());

    /**
     * Try to clone the given object quietly.
     * 
     * @param object
     *            The object to clone.
     * @return The cloned object or null if the clone process failed.
     */
    public static Object cloneObjectQuietly(final Object object) {
        Object clone = null;
        try {
            clone = cloneObject(object);
        } catch (NoSuchMethodException e) {
            logger.error("Try to clone the object with " + "reflection and call the clone method. "
                    + "Thrown exception: NoSuchMethodException", e);
        } catch (SecurityException e) {
            logger.error("Try to clone the object with " + "reflection and call the clone method. "
                    + "Thrown exception: SecurityException", e);
        } catch (IllegalAccessException e) {
            logger.error("Try to clone the object with " + "org.apache.commons.beanutils.BeanUtils failed "
                    + "cause of IllegalAccessException. Could not found from ReflectionUtils.", e);
        } catch (IllegalArgumentException e) {
            logger.error("Try to clone the object with " + "reflection and call the clone method. "
                    + "Thrown exception: IllegalArgumentException", e);
        } catch (InvocationTargetException e) {
            logger.error("Try to clone the object with " + "org.apache.commons.beanutils.BeanUtils failed "
                    + "cause of InvocationTargetException. Could not found from ReflectionUtils.", e);
        } catch (ClassNotFoundException e) {
            logger.error("Try to clone the object with " + "org.apache.commons.beanutils.BeanUtils failed "
                    + "cause of ClassNotFoundException. Could not found from ReflectionUtils.", e);
        } catch (InstantiationException e) {
            logger.error("Try to clone the object with " + "org.apache.commons.beanutils.BeanUtils failed "
                    + "cause of InstantiationException. Could not found from ReflectionUtils.", e);
        } catch (IOException e) {
            logger.error("Try to clone the object with "
                    + "SerializedObjectUtils.copySerializedObject((Serializable)object) " + "cause of IOException.",
                    e);
        }
        return clone;
    }

    /**
     * Try to clone the given object.
     *
     * @param object
     *            The object to clone.
     * @return The cloned object or null if the clone process failed.
     * @throws NoSuchMethodException
     *             the no such method exception
     * @throws SecurityException
     *             Thrown if the security manager indicates a security violation.
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws IllegalArgumentException
     *             the illegal argument exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws ClassNotFoundException
     *             the class not found exception
     * @throws InstantiationException
     *             the instantiation exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Object cloneObject(final Object object)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, ClassNotFoundException, InstantiationException, IOException {
        Object clone = null;
        // Try to clone the object if it implements Serializable.
        if (object instanceof Serializable) {
            clone = SerializedObjectUtils.copySerializedObject((Serializable) object);
            if (clone != null) {
                return clone;
            }
        }
        // Try to clone the object if it is Cloneble.
        if (clone == null && object instanceof Cloneable) {

            if (object.getClass().isArray()) {
                final Class<?> componentType = object.getClass().getComponentType();
                if (componentType.isPrimitive()) {
                    int length = Array.getLength(object);
                    clone = Array.newInstance(componentType, length);
                    while (length-- > 0) {
                        Array.set(clone, length, Array.get(object, length));
                    }
                } else {
                    clone = ((Object[]) object).clone();
                }
                if (clone != null) {
                    return clone;
                }
            }
            Class<?> clazz = object.getClass();
            Method cloneMethod = clazz.getMethod("clone", (Class[]) null);
            clone = cloneMethod.invoke(object, (Object[]) null);
            if (clone != null) {
                return clone;
            }
        }
        // Try to clone the object by copying all his properties with
        // the BeanUtils.copyProperties() method.
        if (clone == null) {
            clone = ReflectionUtils.getNewInstance(object);
            BeanUtils.copyProperties(clone, object);
        }
        return clone;
    }

    /**
     * Try to clone the given generic object.
     *
     * @param <T>
     *            the generic type
     * @param object
     *            the object to clone
     * @return The cloned object or null if the clone process failed.
     */
    @SuppressWarnings("unchecked")
    public static <T> T clone(T object) {
        return (T) cloneObjectQuietly(object);
    }

    /**
     * Compares the given two objects.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @return true, if successful otherwise false
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    @SuppressWarnings("rawtypes")
    public static boolean compare(Object sourceOjbect, Object objectToCompare)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        if (sourceOjbect == null || objectToCompare == null
                || !sourceOjbect.getClass().equals(objectToCompare.getClass())) {
            throw new IllegalArgumentException("Object should not be null and be the same type.");
        }
        Map beanDescription = BeanUtils.describe(sourceOjbect);
        beanDescription.remove("class");
        Map clonedBeanDescription = BeanUtils.describe(objectToCompare);
        clonedBeanDescription.remove("class");
        for (Object key : beanDescription.keySet()) {
            if (compareTo(sourceOjbect, objectToCompare, key.toString()) != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * Gets the changed data.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @return the changed data
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    @SuppressWarnings("rawtypes")
    public static List<ChangedAttributeResult> getChangedData(Object sourceOjbect, Object objectToCompare)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        if (sourceOjbect == null || objectToCompare == null
                || !sourceOjbect.getClass().equals(objectToCompare.getClass())) {
            throw new IllegalArgumentException("Object should not be null and be the same type.");
        }
        Map beanDescription = BeanUtils.describe(sourceOjbect);
        beanDescription.remove("class");
        Map clonedBeanDescription = BeanUtils.describe(objectToCompare);
        clonedBeanDescription.remove("class");
        List<ChangedAttributeResult> changedData = new ArrayList<ChangedAttributeResult>();
        for (Object key : beanDescription.keySet()) {
            if (compareTo(sourceOjbect, objectToCompare, key.toString()) != 0) {
                Object sourceAttribute = beanDescription.get(key);
                Object changedAttribute = clonedBeanDescription.get(key);
                changedData.add(new ChangedAttributeResult(key, sourceAttribute, changedAttribute));
            }
        }
        return changedData;
    }

    /**
     * Compares the given object over the given property.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @param property
     *            the property
     * @return the int
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static int compareTo(Object sourceOjbect, Object objectToCompare, String property)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Map<?, ?> beanDescription = BeanUtils.describe(sourceOjbect);
        beanDescription.remove("class");
        Map<?, ?> clonedBeanDescription = BeanUtils.describe(objectToCompare);
        clonedBeanDescription.remove("class");
        Object sourceAttribute = beanDescription.get(property);
        Object changedAttribute = clonedBeanDescription.get(property);
        if (sourceAttribute == null && changedAttribute == null) {
            return 0;
        }
        if (sourceAttribute != null && changedAttribute == null) {
            return 1;
        } else if (sourceAttribute == null && changedAttribute != null) {
            return -1;
        }
        return new BeanComparator(property).compare(sourceOjbect, objectToCompare);
    }

    /**
     * Compares the given object over the given property quietly.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @param property
     *            the property
     * @return the int
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static int compareToQuietly(Object sourceOjbect, Object objectToCompare, String property) {
        Map<?, ?> beanDescription = null;
        try {
            beanDescription = BeanUtils.describe(sourceOjbect);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            logger.error("BeanUtils.describe(sourceOjbect) throws an exception...", e);
            return 0;
        }
        beanDescription.remove("class");
        Map<?, ?> clonedBeanDescription = null;
        try {
            clonedBeanDescription = BeanUtils.describe(objectToCompare);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            logger.error("BeanUtils.describe(objectToCompare) throws an exception...", e);
            return 0;
        }
        clonedBeanDescription.remove("class");
        Object sourceAttribute = beanDescription.get(property);
        Object changedAttribute = clonedBeanDescription.get(property);
        if (sourceAttribute == null && changedAttribute == null) {
            return 0;
        }
        if (sourceAttribute != null && changedAttribute == null) {
            return 1;
        } else if (sourceAttribute == null && changedAttribute != null) {
            return -1;
        }
        return new BeanComparator(property).compare(sourceOjbect, objectToCompare);
    }

    /**
     * Compares the given two objects and gets the changed data.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @return the changed data
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    @SuppressWarnings("rawtypes")
    public static Map<Object, ChangedAttributeResult> getChangedDataMap(Object sourceOjbect, Object objectToCompare)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        if (sourceOjbect == null || objectToCompare == null
                || !sourceOjbect.getClass().equals(objectToCompare.getClass())) {
            throw new IllegalArgumentException("Object should not be null and be the same type.");
        }
        Map beanDescription = BeanUtils.describe(sourceOjbect);
        beanDescription.remove("class");
        Map clonedBeanDescription = BeanUtils.describe(objectToCompare);
        clonedBeanDescription.remove("class");
        Map<Object, ChangedAttributeResult> changedData = new HashMap<Object, ChangedAttributeResult>();
        for (Object key : beanDescription.keySet()) {
            Object sourceAttribute = beanDescription.get(key);
            Object changedAttribute = clonedBeanDescription.get(key);
            if (compareTo(sourceOjbect, objectToCompare, key.toString()) != 0) {
                changedData.put(key, new ChangedAttributeResult(key, sourceAttribute, changedAttribute));
            }
        }
        return changedData;
    }

    /**
     * Gets the compare to result.
     * 
     * @param sourceOjbect
     *            the source ojbect
     * @param objectToCompare
     *            the object to compare
     * @return the compare to result
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, Integer> getCompareToResult(Object sourceOjbect, Object objectToCompare)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        if (sourceOjbect == null || objectToCompare == null
                || !sourceOjbect.getClass().equals(objectToCompare.getClass())) {
            throw new IllegalArgumentException("Object should not be null and be the same type.");
        }
        Map beanDescription = BeanUtils.describe(sourceOjbect);
        beanDescription.remove("class");
        Map clonedBeanDescription = BeanUtils.describe(objectToCompare);
        clonedBeanDescription.remove("class");
        Map<String, Integer> compareResult = new HashMap<String, Integer>();
        for (Object key : beanDescription.keySet()) {
            compareResult.put(key.toString(),
                    Integer.valueOf(compareTo(sourceOjbect, objectToCompare, key.toString())));
        }
        return compareResult;
    }

    /**
     * Private constructor.
     */
    private ObjectUtils() {
        super();
    }

    /**
     * Copy the given original object to the given destination object.
     * 
     * @param <DESTINATION>
     *            the generic type of the destination object.
     * @param <ORIGINAL>
     *            the generic type of the original object.
     * @param destination
     *            the destination object.
     * @param original
     *            the original object.
     * @throws IllegalAccessException
     *             the illegal access exception
     * @throws InvocationTargetException
     *             the invocation target exception
     */
    public static final <DESTINATION, ORIGINAL> void copy(DESTINATION destination, ORIGINAL original)
            throws IllegalAccessException, InvocationTargetException {
        BeanUtils.copyProperties(destination, original);
    }

    /**
     * Copy quietly the given original object to the given destination object.
     * 
     * @param <DESTINATION>
     *            the generic type of the destination object.
     * @param <ORIGINAL>
     *            the generic type of the original object.
     * @param destination
     *            the destination object.
     * @param original
     *            the original object.
     * @return the destination object.
     */
    public static final <DESTINATION, ORIGINAL> DESTINATION copyQuietly(DESTINATION destination,
            ORIGINAL original) {
        try {
            copy(destination, original);
        } catch (IllegalAccessException e) {
            return null;
        } catch (InvocationTargetException e) {
            return null;
        }
        return destination;
    }

    /**
     * Checks if is copyable and copies if its possible otherwise it returns false.
     * 
     * @param <DESTINATION>
     *            the generic type of the destination object.
     * @param <ORIGINAL>
     *            the generic type of the original object.
     * @param destination
     *            the destination object.
     * @param original
     *            the original object.
     * @return true, if is copyable otherwise false.
     */
    public static final <DESTINATION, ORIGINAL> boolean isCopyable(DESTINATION destination, ORIGINAL original) {
        return copyQuietly(destination, original) != null;
    }

}