Java tutorial
/* * Copyright (c) 2012 Brown Bag Consulting. * This file is part of the ExpressUI project. * Author: Juan Osuna * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License Version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * Brown Bag Consulting, Brown Bag Consulting DISCLAIMS THE WARRANTY OF * NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the ExpressUI software without * disclosing the source code of your own applications. These activities * include: offering paid services to customers as an ASP, providing * services from a web application, shipping ExpressUI with a closed * source product. * * For more information, please contact Brown Bag Consulting at this * address: juan@brownbagconsulting.com. */ package com.expressui.core.util; import com.expressui.core.util.assertion.Assert; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.beanutils.WrapDynaBean; import org.apache.commons.lang.ClassUtils; import org.springframework.beans.BeanUtils; import java.beans.PropertyDescriptor; import java.lang.reflect.*; import java.util.ArrayList; import java.util.Collection; /** * Reflection utility class */ public class ReflectionUtil { /** * Creates new instance from the given type. * * @param type class to reflectively instantiate * @param <T> type of the class * @return new instance */ public static <T> T newInstance(Class<T> type) { try { return type.newInstance(); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Creates new instance from the given type, based on given parameter types and args. * * @param type class to reflectively instantiate * @param <T> type of the class * @param parameterTypes used to find the right constructor * @param args passed to constructor * @return new instance */ public static <T> T newInstance(Class<T> type, Class[] parameterTypes, Object[] args) { try { Constructor constructor = type.getDeclaredConstructor(parameterTypes); constructor.setAccessible(true); return (T) constructor.newInstance(args); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Gets the first generic argument of the given class. * * @param clazz class from which to extract generic argument * @return type of generic argument */ public static Class getGenericArgumentType(Class clazz) { return getGenericArgumentType(clazz, 0); } /** * Gets a generic argument of the given class, based on arg index. * * @param clazz class from which to extract generic argument * @param argIndex index of the declared argument type * @return type of generic argument */ public static Class getGenericArgumentType(Class clazz, int argIndex) { Type type = clazz.getGenericSuperclass(); if (type != null && type instanceof ParameterizedType) { if (((ParameterizedType) type).getActualTypeArguments()[argIndex] instanceof Class) { return (Class) ((ParameterizedType) type).getActualTypeArguments()[argIndex]; } else { return null; } } else { if (!(type instanceof Class) || type.equals(Object.class)) { return null; } else { return getGenericArgumentType((Class) type, argIndex); } } } /** * Gets the value type of the given collection, as declared by the collection property type. * * @param beanType bean class * @param beanProperty name of property, which must be a collection * @return generic type declared for collection members */ public static Class getCollectionValueType(Class beanType, String beanProperty) { PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(beanType, beanProperty); Class propertyType = descriptor.getPropertyType(); Assert.PROGRAMMING.isTrue(Collection.class.isAssignableFrom(propertyType), "Bean property not a collection type: " + beanType + "." + beanProperty); Type genericPropertyType = descriptor.getReadMethod().getGenericReturnType(); Class collectionValueType = null; if (genericPropertyType != null && genericPropertyType instanceof ParameterizedType) { Type[] typeArgs = ((ParameterizedType) genericPropertyType).getActualTypeArguments(); if (typeArgs != null && typeArgs.length > 0) { if (typeArgs.length == 1) { collectionValueType = (Class) typeArgs[0]; } else if (typeArgs.length == 2) { collectionValueType = (Class) typeArgs[1]; } else { Assert.PROGRAMMING.fail("Collection type has more than two generic arguments"); } } } return collectionValueType; } /** * Asks if the bean's properties are empty. boolean properties that are false and numbers * that are zero are considered empty. String values that are zero-length are considered empty. * All other property types must be null to be considered empty. * * @param bean bean to check * @return true if bean has no values */ public static boolean isBeanEmpty(Object bean) { if (bean == null) { return true; } WrapDynaBean wrapDynaBean = new WrapDynaBean(bean); DynaProperty[] properties = wrapDynaBean.getDynaClass().getDynaProperties(); for (DynaProperty property : properties) { String propertyName = property.getName(); Class propertyType = property.getType(); Object value = wrapDynaBean.get(propertyName); if (propertyType.isPrimitive()) { if (value instanceof Number && !value.toString().equals("0")) { return false; } else if (value instanceof Boolean && !value.toString().equals("false")) { return false; } else if (!value.toString().isEmpty()) { return false; } } else if (value != null) { if (!(value instanceof Collection)) { String convertedStringValue = ConvertUtils.convert(value); if (!StringUtil.isEmpty(convertedStringValue)) { return false; } } } } return true; } /** * Finds all properties in the bean that are complex, that is not BeanUtils.isSimpleValueType * * @param bean bean to reflectively analyze * @return collection of properties on the bean */ public static Collection<String> findComplexProperties(Object bean) { Collection<String> complexProperties = new ArrayList<String>(); WrapDynaBean wrapDynaBean = new WrapDynaBean(bean); DynaProperty[] properties = wrapDynaBean.getDynaClass().getDynaProperties(); for (DynaProperty property : properties) { String propertyName = property.getName(); Class propertyType = property.getType(); if (!BeanUtils.isSimpleValueType(propertyType)) { complexProperties.add(propertyName); } } return complexProperties; } /** * Converts object value to given type. Converts primitives to their wrappers. * Converts strings to numbers. * * @param value value to convert * @param type type to convert to * @param <T> type * @return converted value * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws NoSuchMethodException */ public static <T> T convertValue(Object value, Class<T> type) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException { Class clazz; if (type.isPrimitive()) { clazz = ClassUtils.primitiveToWrapper(type); } else { clazz = type; } if (null == value || clazz.isAssignableFrom(value.getClass())) { return (T) value; } Constructor<T> constructor = clazz.getConstructor(new Class[] { String.class }); return constructor.newInstance(value.toString()); } /** * Creates a default value for a primitive type, false for boolean and 0 for everything else. * * @param primitiveType primitive type to create default value for * @return primitive wrapper with default value */ public static Object createDefaultPrimitiveValue(Class primitiveType) { Assert.PROGRAMMING.isTrue(primitiveType.isPrimitive(), "argument must be a primitive type"); if (isBooleanType(primitiveType)) { return false; } else { return 0; } } /** * Asks if given type is a number type. * * @param type type to check * @return true if a number */ public static boolean isNumberType(Class type) { Class clazz; if (type.isPrimitive()) { clazz = ClassUtils.primitiveToWrapper(type); } else { clazz = type; } return Number.class.isAssignableFrom(clazz); } /** * Asks if given type is a boolean type. * * @param type type to check * @return true if a boolean */ public static boolean isBooleanType(Class type) { Class clazz; if (type.isPrimitive()) { clazz = ClassUtils.primitiveToWrapper(type); } else { clazz = type; } return Boolean.class.isAssignableFrom(clazz); } /** * Finds a method on a class. * * @param type class containing the method * @param methodName name of the method to search for * @param parameterTypes parameter types declared in the method signature * @return found method */ public static Method getMethod(Class type, String methodName, Class<?>... parameterTypes) { Method method = null; Class currentType = type; while (method == null && !currentType.equals(Object.class)) { try { method = currentType.getDeclaredMethod(methodName, parameterTypes); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { currentType = currentType.getSuperclass(); } } return method; } /** * Finds field on a given type. * * @param type class containing the field * @param fieldName name of field to search for * @return found field */ public static Field getField(Class type, String fieldName) { Field field = null; Class currentType = type; while (field == null && !currentType.equals(Object.class)) { try { field = currentType.getDeclaredField(fieldName); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { currentType = currentType.getSuperclass(); } } return field; } }