net.solarnetwork.util.ClassUtils.java Source code

Java tutorial

Introduction

Here is the source code for net.solarnetwork.util.ClassUtils.java

Source

/* ===================================================================
 * ClassUtils.java
 * 
 * Created Jul 15, 2008 8:20:38 AM
 * 
 * This program 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.
 * 
 * This program 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 this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
 * 02111-1307 USA
 * ===================================================================
 * $Id$
 * ===================================================================
 */

package net.solarnetwork.util;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.StringUtils;

/**
 * Utility methods for dealing with classes at runtime.
 *
 * @author matt
 * @version $Revision$ $Date$
 */
public final class ClassUtils {

    private static final Set<String> DEFAULT_BEAN_PROP_NAME_IGNORE = new HashSet<String>(
            Arrays.asList(new String[] { "class" }));
    private static final Logger LOG = LoggerFactory.getLogger(ClassUtils.class);

    /* Do not instantiate me. */
    private ClassUtils() {
        super();
    }

    /**
     * Instantiate a class of a specific interface type.
     * 
     * @param <T> the desired interface type
     * @param className the class name that implements the interface
     * @param type the desired interface
     * @return new instance of the desired type
     */
    public static <T> T instantiateClass(String className, Class<T> type) {
        Class<? extends T> clazz = loadClass(className, type);
        try {
            T o = clazz.newInstance();
            return o;
        } catch (Exception e) {
            throw new RuntimeException("Unable to instantiate class [" + className + ']', e);
        }
    }

    /**
     * Load a class of a particular type.
     * 
     * <p>This uses the {@code type}'s ClassLoader to load the class. If that is 
     * not available, it will use the current thread's context class loader.</p>
     * 
     * @param <T> the desired interface type
     * @param className the class name that implements the interface
     * @param type the desired interface
     * @return the class
     */
    public static <T> Class<? extends T> loadClass(String className, Class<T> type) {
        try {
            ClassLoader loader = type.getClassLoader();
            if (loader == null) {
                loader = Thread.currentThread().getContextClassLoader();
            }
            Class<?> clazz = loader.loadClass(className);
            if (!type.isAssignableFrom(clazz)) {
                throw new RuntimeException("Class [" + clazz + "] is not a [" + type + ']');
            }
            return clazz.asSubclass(type);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Unable to load class [" + className + ']', e);
        }
    }

    /**
     * Set bean property values on an object from a Map.
     * 
     * @param o the bean to set JavaBean properties on
     * @param values a Map of JavaBean property names and their corresponding values to set
     */
    public static void setBeanProperties(Object o, Map<String, ?> values) {
        BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(o);
        bean.setPropertyValues(values);
    }

    /**
     * Get a Map of non-null bean properties for an object.
     * 
     * @param o the object to inspect
     * @param ignore a set of property names to ignore (optional)
     * @return Map (never null)
     */
    public static Map<String, Object> getBeanProperties(Object o, Set<String> ignore) {
        if (ignore == null) {
            ignore = DEFAULT_BEAN_PROP_NAME_IGNORE;
        }
        Map<String, Object> result = new LinkedHashMap<String, Object>();
        BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(o);
        PropertyDescriptor[] props = bean.getPropertyDescriptors();
        for (PropertyDescriptor prop : props) {
            if (prop.getReadMethod() == null) {
                continue;
            }
            String propName = prop.getName();
            if (ignore != null && ignore.contains(propName)) {
                continue;
            }
            Object propValue = bean.getPropertyValue(propName);
            if (propValue == null) {
                continue;
            }
            result.put(propName, propValue);
        }
        return result;
    }

    /**
     * Copy non-null bean properties from one object to another.
     * 
     * @param src the object to copy values from
     * @param dest the object to copy values to
     * @param ignore a set of property names to ignore (optional)
     * where <em>null</em>
     */
    public static void copyBeanProperties(Object src, Object dest, Set<String> ignore) {
        copyBeanProperties(src, dest, ignore, false);
    }

    /**
     * Copy non-null bean properties from one object to another.
     * 
     * @param src the object to copy values from
     * @param dest the object to copy values to
     * @param ignore a set of property names to ignore (optional)
     * @param emptyStringToNull if <em>true</em> then String values that 
     * are empty or contain only whitespace will be treated as if they
     * where <em>null</em>
     */
    public static void copyBeanProperties(Object src, Object dest, Set<String> ignore, boolean emptyStringToNull) {
        if (ignore == null) {
            ignore = DEFAULT_BEAN_PROP_NAME_IGNORE;
        }
        BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(src);
        BeanWrapper to = PropertyAccessorFactory.forBeanPropertyAccess(dest);
        PropertyDescriptor[] props = bean.getPropertyDescriptors();
        for (PropertyDescriptor prop : props) {
            if (prop.getReadMethod() == null) {
                continue;
            }
            String propName = prop.getName();
            if (ignore != null && ignore.contains(propName)) {
                continue;
            }
            Object propValue = bean.getPropertyValue(propName);
            if (propValue == null || (emptyStringToNull && (propValue instanceof String)
                    && !StringUtils.hasText((String) propValue))) {
                continue;
            }
            if (to.isWritableProperty(propName)) {
                to.setPropertyValue(propName, propValue);
            }
        }
    }

    /**
     * Get a Map of non-null bean properties for an object.
     * 
     * @param o the object to inspect
     * @param ignore a set of property names to ignore (optional)
     * @param serializeIgnore if <em>true</em> test for the {@link SerializeIgnore}
     * annotation for ignoring properties
     * @return Map (never null)
     */
    public static Map<String, Object> getBeanProperties(Object o, Set<String> ignore, boolean serializeIgnore) {
        if (o == null) {
            return null;
        }
        if (ignore == null) {
            ignore = DEFAULT_BEAN_PROP_NAME_IGNORE;
        }
        Map<String, Object> result = new LinkedHashMap<String, Object>();
        BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(o);
        PropertyDescriptor[] props = bean.getPropertyDescriptors();
        for (PropertyDescriptor prop : props) {
            if (prop.getReadMethod() == null) {
                continue;
            }
            String propName = prop.getName();
            if (ignore != null && ignore.contains(propName)) {
                continue;
            }
            Object propValue = bean.getPropertyValue(propName);
            if (propValue == null) {
                continue;
            }
            if (serializeIgnore) {
                Method getter = prop.getReadMethod();
                if (getter != null && getter.isAnnotationPresent(SerializeIgnore.class)) {
                    continue;
                }
            }
            result.put(propName, propValue);
        }
        return result;
    }

    /**
     * Load a classpath SQL resource into a String.
     * 
     * @param resourceName the SQL resource to load
     * @param clazz the Class to load the resource from
     * @return the String
     */
    public static String getResourceAsString(String resourceName, Class<?> clazz) {
        InputStream in = clazz.getResourceAsStream(resourceName);
        if (in == null) {
            throw new RuntimeException("Fesource [" + resourceName + "] not found");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[4096];
            int bytesRead = -1;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            out.flush();
            return out.toString();
        } catch (IOException e) {
            throw new RuntimeException("Error reading resource [" + resourceName + ']', e);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                LOG.warn("Could not close InputStream", ex);
            }
            try {
                out.close();
            } catch (IOException ex) {
                LOG.warn("Could not close OutputStream", ex);
            }
        }
    }

}