/**
*
*/
package org.minnal.utils.reflection;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.reflect.TypeToken;
/**
* @author ganeshs
*
*/
public class PropertyUtil {
private static final Logger logger = LoggerFactory.getLogger(PropertyUtil.class);
/**
* Check if the given type represents a "simple" property:
* a primitive, a String or other CharSequence, a Number, a Date,
* a URI, a URL, a Locale, a Class, or a corresponding array.
* <p>Used to determine properties to check for a "simple" dependency-check.
* @param clazz the type to check
* @return whether the given type represents a "simple" property
* @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE
* @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies
*/
public static boolean isSimpleProperty(Class<?> clazz) {
return isSimpleValueType(clazz) || (clazz.isArray() && isSimpleValueType(clazz.getComponentType()));
}
/**
* Check if the given type represents a "simple" value type:
* a primitive, a String or other CharSequence, a Number, a Date,
* a URI, a URL, a Locale or a Class.
*
* @param clazz the type to check
* @return whether the given type represents a "simple" value type
*/
public static boolean isSimpleValueType(Class<?> clazz) {
return ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||
CharSequence.class.isAssignableFrom(clazz) ||
Number.class.isAssignableFrom(clazz) ||
Date.class.isAssignableFrom(clazz) ||
clazz.equals(URI.class) || clazz.equals(URL.class) ||
clazz.equals(Locale.class) || clazz.equals(Class.class) ||
clazz.equals(Serializable.class) || clazz.equals(Timestamp.class);
}
public static boolean isCollectionProperty(Type type, boolean includeMaps) {
if (type instanceof Class) {
return isCollectionProperty((Class<?>)type, includeMaps);
}
if (type instanceof ParameterizedType) {
return isCollectionProperty((Class<?>)((ParameterizedType) type).getRawType(), includeMaps);
}
return false;
}
public static boolean isCollectionProperty(Class<?> clazz, boolean includeMaps) {
return Collection.class.isAssignableFrom(clazz) || (includeMaps && isMapProperty(clazz));
}
public static boolean isMapProperty(Type type) {
if (type instanceof Class) {
return isMapProperty((Class<?>)type);
}
if (type instanceof ParameterizedType) {
return isMapProperty((Class<?>)((ParameterizedType) type).getRawType());
}
return false;
}
public static boolean isMapProperty(Class<?> clazz) {
return Map.class.isAssignableFrom(clazz);
}
public static Class<?> getCollectionElementType(Type type) {
ParameterizedType ptype = (ParameterizedType) type;
Class<?> rawType = (Class<?>) ptype.getRawType();
try {
if (Collection.class.isAssignableFrom(rawType)) {
return TypeToken.of(type).resolveType(Collection.class.getMethod("add", Object.class).getGenericParameterTypes()[0]).getRawType();
}
if (Map.class.isAssignableFrom(rawType)) {
return TypeToken.of(type).resolveType(Map.class.getMethod("put", Object.class, Object.class).getGenericParameterTypes()[1]).getRawType();
}
} catch (RuntimeException e) {
logger.trace("Failed while getting the collection element type - " + type, e);
} catch (NoSuchMethodException e) {
logger.trace("Failed while getting the collection element type - " + type, e);
}
return Object.class;
}
public static <T extends Annotation> T getAnnotation(PropertyDescriptor descriptor, Class<T> clazz) {
return getAnnotation(descriptor, clazz, false);
}
public static <T extends Annotation> T getAnnotation(PropertyDescriptor descriptor, Class<T> clazz, boolean ignoreObjectClass) {
Method method = descriptor.getReadMethod();
if (method == null || ignoreObjectClass && method.getDeclaringClass().equals(Object.class)) {
return null;
}
Field field = FieldUtils.getField(method.getDeclaringClass(), descriptor.getName(), true);
if (field == null) {
return null;
}
if (field.isAnnotationPresent(clazz)) {
return field.getAnnotation(clazz);
}
return method.getAnnotation(clazz);
}
public static boolean hasAnnotation(PropertyDescriptor descriptor, Class<? extends Annotation> clazz) {
return hasAnnotation(descriptor, clazz, false);
}
public static boolean hasAnnotation(PropertyDescriptor descriptor, Class<? extends Annotation> clazz, boolean ignoreObjectClass) {
return getAnnotation(descriptor, clazz) != null;
}
public static List<String> getEnumValues(PropertyDescriptor descriptor) {
List<String> values = new ArrayList<String>();
try {
Enum<?>[] enums = (Enum[])descriptor.getPropertyType().getMethod("values").invoke(null);
for (Enum<?> enm : enums) {
values.add(enm.name());
}
} catch (RuntimeException e) {
logger.trace("Failed while getting the enum values for the descriptor - " + descriptor, e);
} catch (Exception e) {
logger.trace("Failed while getting the enum values for the descriptor - " + descriptor, e);
}
return values;
}
public static Class<?> getType(PropertyDescriptor descriptor) {
Method method = descriptor.getReadMethod();
if (method == null) {
method = descriptor.getWriteMethod();
}
if (method == null) {
return null;
}
Type type = method.getGenericReturnType();
if (type instanceof ParameterizedType) {
if (isCollectionProperty(type, true)) {
return getCollectionElementType(type);
}
return (Class<?>)((ParameterizedType)type).getRawType();
}
return (Class<?>) type;
}
public static List<PropertyDescriptor> getPopertiesWithAnnotation(Class<?> clazz, Class<? extends Annotation> annotation) {
List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>();
for (PropertyDescriptor descriptor : PropertyUtils.getPropertyDescriptors(clazz)) {
if (hasAnnotation(descriptor, annotation)) {
descriptors.add(descriptor);
}
}
return descriptors;
}
}