All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.solarnetwork.util.ClassUtils Maven / Gradle / Ivy

There is a newer version: 3.27.0
Show newest version
/* ===================================================================
 * 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
 * ===================================================================
 */

package net.solarnetwork.util;

import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.PropertyBatchUpdateException;
import org.springframework.util.StringUtils;
import net.solarnetwork.domain.SerializeIgnore;

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

	/**
	 * A set of package name prefix values representing built-in Java classes.
	 * 
	 * 

* This can be useful as an exclusion set in the * {@link #getAllInterfacesForClassAsSet(Class, Set)} method. *

* * @since 1.3 */ public static final Set JAVA_PACKAGE_PREFIXES = Collections .unmodifiableSet(new HashSet(Arrays.asList("java.", "javax."))); private static final Set DEFAULT_BEAN_PROP_NAME_IGNORE = new HashSet( Arrays.asList(new String[] { "class" })); /* Do not instantiate me. */ private ClassUtils() { super(); } /** * Instantiate a class of a specific interface type. * * @param * 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 instantiateClass(String className, Class type) { Class 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. * *

* 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. *

* * @param * the desired interface type * @param className * the class name that implements the interface * @param type * the desired interface * @return the class */ public static Class loadClass(String className, Class 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 values) { BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(o); bean.setAutoGrowNestedPaths(true); bean.setPropertyValues(values); } /** * 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. * @param ignoreErrors * Flag to ignore unknown and invalid properties. * @since 1.1 */ public static void setBeanProperties(Object o, Map values, boolean ignoreErrors) { if ( o == null || values == null ) { return; } BeanWrapper bean = PropertyAccessorFactory.forBeanPropertyAccess(o); bean.setAutoGrowNestedPaths(true); MutablePropertyValues pvs = new MutablePropertyValues(values); try { bean.setPropertyValues(pvs, ignoreErrors, ignoreErrors); } catch ( PropertyBatchUpdateException e ) { if ( ignoreErrors == false ) { throw e; } } } /** * 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 getBeanProperties(Object o, Set ignore) { if ( ignore == null ) { ignore = DEFAULT_BEAN_PROP_NAME_IGNORE; } Map result = new LinkedHashMap(); 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; } /** * Get a Map of non-null simple bean properties for an object. * * @param o * the object to inspect * @param ignore * a set of property names to ignore (optional) * @return Map (never {@literal null}) * @since 1.1 */ public static Map getSimpleBeanProperties(Object o, Set ignore) { if ( ignore == null ) { ignore = DEFAULT_BEAN_PROP_NAME_IGNORE; } Map result = new LinkedHashMap(); 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; } Class propType = bean.getPropertyType(propName); if ( !(propType.isPrimitive() || propType.isEnum() || String.class.isAssignableFrom(propType) || Number.class.isAssignableFrom(propType) || Character.class.isAssignableFrom(propType) || Byte.class.isAssignableFrom(propType) || Date.class.isAssignableFrom(propType)) ) { continue; } Object propValue = bean.getPropertyValue(propName); if ( propValue == null ) { continue; } if ( propType.isEnum() ) { propValue = propValue.toString(); } else if ( Date.class.isAssignableFrom(propType) ) { propValue = ((Date) propValue).getTime(); } 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 {@literal null} */ public static void copyBeanProperties(Object src, Object dest, Set 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 {@literal true} then String values that are empty or contain only * whitespace will be treated as if they where {@literal null} */ public static void copyBeanProperties(Object src, Object dest, Set 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 {@literal true} test for the {@link SerializeIgnore} annotation * for ignoring properties * @return Map (never null) */ public static Map getBeanProperties(Object o, Set ignore, boolean serializeIgnore) { if ( o == null ) { return null; } if ( ignore == null ) { ignore = DEFAULT_BEAN_PROP_NAME_IGNORE; } Map result = new LinkedHashMap(); 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 textual classpath resource into a String. * * @param resourceName * the resource to load * @param clazz * the Class to load the resource from * @return the String */ public static String getResourceAsString(String resourceName, Class clazz) { return getResourceAsString(resourceName, clazz, null); } /** * Load a textual classpath resource into a String. * * @param resourceName * the resource to load * @param clazz * the Class to load the resource from * @param skip * an optional pattern that will be used to match against lines; * matches will be left out of the string used to match * @return the text * @throws RuntimeException * if the resource cannot be loaded * @since 1.3 */ public static String getResourceAsString(String resourceName, Class clazz, Pattern skip) { try (InputStream in = clazz.getResourceAsStream(resourceName)) { if ( in == null ) { throw new RuntimeException( "Resource " + resourceName + " not found from class " + clazz.getName() + "."); } StringBuilder buf = new StringBuilder(512); try (BufferedReader r = new BufferedReader( new InputStreamReader(in, Charset.forName("UTF-8")))) { while ( true ) { String line = r.readLine(); if ( line == null ) { break; } if ( skip != null && skip.matcher(line).find() ) { continue; } buf.append(line).append("\n"); } } if ( buf.length() > 0 ) { // remove trailing newline buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } catch ( IOException e ) { throw new RuntimeException("Error reading resource [" + resourceName + "]", e); } } private static void addClassesToSetUnlessExcludedByPackagePrefix(Collection> classes, Set> set, Set excluding) { if ( classes == null ) { return; } if ( excluding != null ) { for ( Class clazz : classes ) { String fqn = clazz.getName(); for ( String prefix : excluding ) { if ( fqn.startsWith(prefix) ) { return; } } } } set.addAll(classes); } /** * Get all interfaces implemented by a class, excluding those in the * {@link #JAVA_PACKAGE_PREFIXES} package set. * * @param clazz * the class to get all implemented interfaces for * @return the set of interfaces * @since 1.1 */ public static Set> getAllNonJavaInterfacesForClassAsSet(Class clazz) { return getAllInterfacesForClassAsSet(clazz, JAVA_PACKAGE_PREFIXES); } /** * Get a set of interfaces implemented by a class and any superclasses or * extended interfaces, optionally excluding based on a set of name prefix * values. * *

* The iteration order of the returned set will be equal to the order * returned by {@link Class#getInterfaces()} method, in reverse class * hierarchy order. *

* * @param clazz * the class to get all implemented interfaces for * @param excluding * a set of class name prefix values to exclude from the results * @return the set of interfaces * @since 1.1 */ public static Set> getAllInterfacesForClassAsSet(Class clazz, Set excluding) { Set> interfaces = new LinkedHashSet>(); while ( clazz != null ) { if ( clazz.isInterface() ) { Set> classes = Collections.> singleton(clazz); addClassesToSetUnlessExcludedByPackagePrefix(classes, interfaces, excluding); } Class[] ifcs = clazz.getInterfaces(); for ( Class ifc : ifcs ) { addClassesToSetUnlessExcludedByPackagePrefix( getAllInterfacesForClassAsSet(ifc, excluding), interfaces, excluding); } clazz = clazz.getSuperclass(); } return interfaces; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy