org.kuali.common.util.ReflectionUtils Maven / Gradle / Ivy
/**
* Copyright 2010-2014 The Kuali Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
*
* 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 org.kuali.common.util;
import static com.google.common.base.Optional.fromNullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static org.kuali.common.util.base.Exceptions.illegalState;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.util.MethodInvoker;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class ReflectionUtils extends org.springframework.util.ReflectionUtils {
/**
* Returns the path from {@code java.lang.Object}, to {@code type}. The last element in the list is {@code type}.
*/
public static List> getTypeHierarchy(Class> type) {
List> list = Lists.newArrayList();
if (type.getSuperclass() != null) {
list.addAll(getTypeHierarchy(type.getSuperclass()));
}
list.add(type);
return list;
}
/**
* Return a map containing every parameterized interface implemented by {@code type}, includes interfaces implemented by super classes
*/
public static Map, ParameterizedType> getAllParameterizedInterfaces(Class> type) {
List list = getAllGenericInterfaces(type);
Map, ParameterizedType> map = Maps.newHashMap();
for (Type element : list) {
if (element instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) element;
Class> interfaceClass = (Class>) pType.getRawType();
map.put(interfaceClass, pType);
}
}
return map;
}
/**
* Return a list containing every interface implemented by {@code type}, includes interfaces implemented by super classes. Type objects returned accurately reflect the actual
* type parameters used in the source code.
*/
public static List getAllGenericInterfaces(Class> type) {
List> path = getTypeHierarchy(type);
List list = Lists.newArrayList();
for (Class> element : path) {
Type[] interfaces = element.getGenericInterfaces();
list.addAll(ImmutableList.copyOf(interfaces));
}
return list;
}
/**
* Return true if this class is declared as final
*/
public static boolean isFinal(Class> type) {
return Modifier.isFinal(type.getModifiers());
}
/**
* Return true if this field is declared as final
*/
public static boolean isFinal(Field field) {
return Modifier.isFinal(field.getModifiers());
}
/**
* Return true if this class is an immutable Guava collection
*/
public static boolean isImmutableGuavaCollection(Class> type) {
return ImmutableCollection.class.isAssignableFrom(type);
}
/**
* Return true if this class is an immutable Guava map
*/
public static boolean isImmutableGuavaMap(Class> type) {
return ImmutableMap.class.isAssignableFrom(type);
}
/**
* Return true if this field is a {@code java.util.Collection}
*/
public static boolean isCollection(Field field) {
return Collection.class.isAssignableFrom(field.getType());
}
/**
* Return true if this field is a {@code java.util.Collection}
*/
public static boolean isStringCollection(Field field) {
return isCollection(field) && hasMatchingParameterizedArgTypes(field, String.class);
}
/**
* Return true if this field is a {@code java.util.Map}
*/
public static boolean isMap(Field field) {
return Map.class.isAssignableFrom(field.getType());
}
/**
* Return true if this field extends from {@code java.util.Map} and uses {@code String} for its keys
*
*
* Map<String,String> returns true
* Map<String,Object> returns true
* Map<String,Integer> returns true
* Map<Integer,String> returns false
*
*/
public static boolean isStringKeyedMap(Field field) {
return isMap(field) && hasMatchingParameterizedArgTypes(field, String.class);
}
/**
* Return true if this field is a {@code java.lang.String}
*/
public static boolean isString(Field field) {
// Safe to do this since java.lang.String is final
return field.getType() == String.class;
}
/**
* Return true if this field is a CharSequence
*/
public static boolean isCharSequence(Field field) {
return isCharSequence(field.getType());
}
/**
* Return true if this field is a CharSequence
*/
public static boolean isCharSequence(Class> type) {
return CharSequence.class.isAssignableFrom(type);
}
/**
* Return true iff this field is a Guava {@code com.google.common.base.Optional}
*/
public static boolean isOptional(Field field) {
return Optional.class.isAssignableFrom(field.getType());
}
/**
* Return true iff this field is a Guava {@code com.google.common.base.Optional}
*/
public static boolean isOptionalString(Field field) {
return isOptional(field) && hasMatchingParameterizedArgTypes(field, String.class);
}
/**
*
* Return true if this field is a generic whose argument types match {@code expectedTypeArguments}
*
*
* For example to match a field declared as {@code Collection}
*
*
* hasMatchingParameterizedArgTypes(myField, String.class)
*
*/
public static boolean hasMatchingParameterizedArgTypes(Field field, Class>... expectedTypeArguments) {
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
return hasMatchingActualTypeArguments(parameterizedType, expectedTypeArguments);
} else {
return false;
}
}
protected static boolean hasMatchingActualTypeArguments(ParameterizedType type, Class>... expectedTypeArguments) {
Type[] actualTypeArguments = type.getActualTypeArguments();
for (int i = 0; i < expectedTypeArguments.length; i++) {
Class> expectedTypeArgument = expectedTypeArguments[i];
if (i >= actualTypeArguments.length) {
return false;
}
if (!(actualTypeArguments[i] instanceof Class>)) {
return false;
}
Class> actualTypeArgument = (Class>) actualTypeArguments[i];
if (actualTypeArgument != expectedTypeArgument) {
return false;
}
}
return true;
}
/**
*
* Throw an exception unless {@code child} is the same as {@code parent} OR descends from {@code parent}. If {@code child} is a primitive type, throw an exception unless
* both {@code child} and {@code parent} are the exact same primitive type.
*
*
* @see equalsOrDescendsFrom
*
* @throws IllegalArgumentException
* if {@code equalsOrDescendsFrom(child,parent)} returns {@code false}
*/
public static void validateIsSuperType(Class> superType, Class> type) {
boolean expression = isSuperType(superType, type);
Preconditions.checkArgument(expression, "[%s] must descend from (or be) [%s]", type.getCanonicalName(), superType.getCanonicalName());
}
/**
*
* Return true if {@code type} descends from {@code superType} OR is the same as {@code superType}. If {@code type} is a primitive type, return {@code true} only if both
* {@code type} and {@code superType} are the exact same primitive type.
*
*/
public static boolean isSuperType(Class> superType, Class> type) {
return superType.isAssignableFrom(type);
}
/**
*
* @deprecated Use Annotations.get() instead
*/
@Deprecated
public static Optional getAnnotation(Class> type, Class annotationClass) {
return Optional.fromNullable(type.getAnnotation(annotationClass));
}
/**
*
* @deprecated Use Annotations.get() instead
*/
@Deprecated
public static Optional getAnnotation(Field field, Class annotationClass) {
return Optional.fromNullable(field.getAnnotation(annotationClass));
}
public static List> getDeclarationHierarchy(Class> type) {
List> hierarchy = new ArrayList>();
Class> declaringClass = type.getDeclaringClass();
if (declaringClass != null) {
hierarchy.addAll(getDeclarationHierarchy(declaringClass));
}
hierarchy.add(type);
return hierarchy;
}
public static String getDeclarationPath(Class> type) {
List> hierarchy = getDeclarationHierarchy(type);
List names = newArrayList();
for (Class> element : hierarchy) {
names.add(element.getSimpleName());
}
return Joiner.on('.').join(names);
}
/**
* Unconditionally attempt to get the value of this field on this bean. If the field is not accessible make it accessible, get the value, then revert the field back to being
* inaccessible.
*/
public static Optional
© 2015 - 2024 Weber Informatics LLC | Privacy Policy