org.reflections.ReflectionUtils Maven / Gradle / Ivy
Show all versions of swagger-all Show documentation
package org.reflections;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.reflections.util.ClasspathHelper;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.Pattern;
import static org.reflections.util.Utils.isEmpty;
/** convenient java reflection helper methods
*
* 1. some helper methods to get type by name: {@link #forName(String, ClassLoader...)} and {@link #forNames(Iterable, ClassLoader...)}
*
* 2. some helper methods to get all types/methods/fields/constructors/properties matching some predicates, generally:
*
Set<?> result = getAllXXX(type/s, withYYY)
* where get methods are:
*
* - {@link #getAllSuperTypes(Class, com.google.common.base.Predicate...)}
*
- {@link #getAllFields(Class, com.google.common.base.Predicate...)}
*
- {@link #getAllMethods(Class, com.google.common.base.Predicate...)}
*
- {@link #getAllConstructors(Class, com.google.common.base.Predicate...)}
*
* and predicates included here all starts with "with", such as
*
* - {@link #withAnnotation(java.lang.annotation.Annotation)}
*
- {@link #withModifier(int)}
*
- {@link #withName(String)}
*
- {@link #withParameters(Class[])}
*
- {@link #withAnyParameterAnnotation(Class)}
*
- {@link #withParametersAssignableTo(Class[])}
*
- {@link #withPrefix(String)}
*
- {@link #withReturnType(Class)}
*
- {@link #withType(Class)}
*
- {@link #withTypeAssignableTo}
*
*
*
* for example, getting all getters would be:
*
* Set<Method> getters = getAllMethods(someClasses,
* Predicates.and(
* withModifier(Modifier.PUBLIC),
* withPrefix("get"),
* withParametersCount(0)));
*
* */
@SuppressWarnings("unchecked")
public abstract class ReflectionUtils {
/** would include {@code Object.class} when {@link #getAllSuperTypes(Class, com.google.common.base.Predicate[])}. default is false. */
public static boolean includeObject = false;
/** get all super types of given {@code type}, including, optionally filtered by {@code predicates}
* include {@code Object.class} if {@link #includeObject} is true */
public static Set> getAllSuperTypes(final Class> type, Predicate super Class>>... predicates) {
Set> result = Sets.newLinkedHashSet();
if (type != null && (includeObject || !type.equals(Object.class))) {
result.add(type);
result.addAll(getAllSuperTypes(type.getSuperclass()));
for (Class> ifc : type.getInterfaces()) result.addAll(getAllSuperTypes(ifc));
}
return filter(result, predicates);
}
/** get all methods of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set getAllMethods(final Class> type, Predicate super Method>... predicates) {
Set result = Sets.newHashSet();
for (Class> t : getAllSuperTypes(type)) {
result.addAll(getMethods(t, predicates));
}
return result;
}
/** get methods of given {@code type}, optionally filtered by {@code predicates} */
public static Set getMethods(Class> t, Predicate super Method>... predicates) {
return filter(t.isInterface() ? t.getMethods() : t.getDeclaredMethods(), predicates);
}
/** get all constructors of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set getAllConstructors(final Class> type, Predicate super Constructor>... predicates) {
Set result = Sets.newHashSet();
for (Class> t : getAllSuperTypes(type)) {
result.addAll(getConstructors(t, predicates));
}
return result;
}
/** get constructors of given {@code type}, optionally filtered by {@code predicates} */
public static Set getConstructors(Class> t, Predicate super Constructor>... predicates) {
return ReflectionUtils.filter(t.getDeclaredConstructors(), predicates); //explicit needed only for jdk1.5
}
/** get all fields of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set getAllFields(final Class> type, Predicate super Field>... predicates) {
Set result = Sets.newHashSet();
for (Class> t : getAllSuperTypes(type)) result.addAll(getFields(t, predicates));
return result;
}
/** get fields of given {@code type}, optionally filtered by {@code predicates} */
public static Set getFields(Class> type, Predicate super Field>... predicates) {
return filter(type.getDeclaredFields(), predicates);
}
/** get all annotations of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set getAllAnnotations(T type, Predicate... predicates) {
Set result = Sets.newHashSet();
if (type instanceof Class) {
for (Class> t : getAllSuperTypes((Class>) type)) {
result.addAll(getAnnotations(t, predicates));
}
} else {
result.addAll(getAnnotations(type, predicates));
}
return result;
}
/** get annotations of given {@code type}, optionally honorInherited, optionally filtered by {@code predicates} */
public static Set getAnnotations(T type, Predicate... predicates) {
return filter(type.getDeclaredAnnotations(), predicates);
}
/** filter all given {@code elements} with {@code predicates}, if given */
public static Set getAll(final Set elements, Predicate super T>... predicates) {
return isEmpty(predicates) ? elements : Sets.newHashSet(Iterables.filter(elements, Predicates.and(predicates)));
}
//predicates
/** where member name equals given {@code name} */
public static Predicate withName(final String name) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && input.getName().equals(name);
}
};
}
/** where member name startsWith given {@code prefix} */
public static Predicate withPrefix(final String prefix) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && input.getName().startsWith(prefix);
}
};
}
/** where member's {@code toString} matches given {@code regex}
* for example:
*
* getAllMethods(someClass, withPattern("public void .*"))
*
* */
public static Predicate withPattern(final String regex) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return Pattern.matches(regex, input.toString());
}
};
}
/** where element is annotated with given {@code annotation} */
public static Predicate withAnnotation(final Class extends Annotation> annotation) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && input.isAnnotationPresent(annotation);
}
};
}
/** where element is annotated with given {@code annotations} */
public static Predicate withAnnotations(final Class extends Annotation>... annotations) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && Arrays.equals(annotations, annotationTypes(input.getAnnotations()));
}
};
}
/** where element is annotated with given {@code annotation}, including member matching */
public static Predicate withAnnotation(final Annotation annotation) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && input.isAnnotationPresent(annotation.annotationType()) &&
areAnnotationMembersMatching(input.getAnnotation(annotation.annotationType()), annotation);
}
};
}
/** where element is annotated with given {@code annotations}, including member matching */
public static Predicate withAnnotations(final Annotation... annotations) {
return new Predicate() {
public boolean apply(@Nullable T input) {
if (input != null) {
Annotation[] inputAnnotations = input.getAnnotations();
if (inputAnnotations.length == annotations.length) {
for (int i = 0; i < inputAnnotations.length; i++) {
if (!areAnnotationMembersMatching(inputAnnotations[i], annotations[i])) return false;
}
}
}
return true;
}
};
}
/** when method/constructor parameter types equals given {@code types} */
public static Predicate withParameters(final Class>... types) {
return new Predicate() {
public boolean apply(@Nullable Member input) {
return Arrays.equals(parameterTypes(input), types);
}
};
}
/** when member parameter types assignable to given {@code types} */
public static Predicate withParametersAssignableTo(final Class... types) {
return new Predicate() {
public boolean apply(@Nullable Member input) {
if (input != null) {
Class>[] parameterTypes = parameterTypes(input);
if (parameterTypes.length == types.length) {
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].isAssignableFrom(types[i]) ||
(parameterTypes[i] == Object.class && types[i] != Object.class)) {
return false;
}
}
return true;
}
}
return false;
}
};
}
/** when method/constructor parameters count equal given {@code count} */
public static Predicate withParametersCount(final int count) {
return new Predicate() {
public boolean apply(@Nullable Member input) {
return input != null && parameterTypes(input).length == count;
}
};
}
/** when method/constructor has any parameter with an annotation matches given {@code annotations} */
public static Predicate withAnyParameterAnnotation(final Class extends Annotation> annotationClass) {
return new Predicate() {
public boolean apply(@Nullable Member input) {
return input != null && Iterables.any(annotationTypes(parameterAnnotations(input)), new Predicate>() {
public boolean apply(@Nullable Class extends Annotation> input) {
return input.equals(annotationClass);
}
});
}
};
}
/** when method/constructor has any parameter with an annotation matches given {@code annotations}, including member matching */
public static Predicate withAnyParameterAnnotation(final Annotation annotation) {
return new Predicate() {
public boolean apply(@Nullable Member input) {
return input != null && Iterables.any(parameterAnnotations(input), new Predicate() {
public boolean apply(@Nullable Annotation input) {
return areAnnotationMembersMatching(annotation, input);
}
});
}
};
}
/** when field type equal given {@code type} */
public static Predicate withType(final Class type) {
return new Predicate() {
public boolean apply(@Nullable Field input) {
return input != null && input.getType().equals(type);
}
};
}
/** when field type assignable to given {@code type} */
public static Predicate withTypeAssignableTo(final Class type) {
return new Predicate() {
public boolean apply(@Nullable Field input) {
return input != null && type.isAssignableFrom(input.getType());
}
};
}
/** when method return type equal given {@code type} */
public static Predicate withReturnType(final Class type) {
return new Predicate() {
public boolean apply(@Nullable Method input) {
return input != null && input.getReturnType().equals(type);
}
};
}
/** when method return type assignable from given {@code type} */
public static Predicate withReturnTypeAssignableTo(final Class type) {
return new Predicate() {
public boolean apply(@Nullable Method input) {
return input != null && type.isAssignableFrom(input.getReturnType());
}
};
}
/** when member modifier matches given {@code mod}
* for example:
*
* withModifier(Modifier.PUBLIC)
*
*/
public static Predicate withModifier(final int mod) {
return new Predicate() {
public boolean apply(@Nullable T input) {
return input != null && (input.getModifiers() & mod) != 0;
}
};
}
/** when class modifier matches given {@code mod}
* for example:
*
* withModifier(Modifier.PUBLIC)
*
*/
public static Predicate> withClassModifier(final int mod) {
return new Predicate>() {
public boolean apply(@Nullable Class> input) {
return input != null && (input.getModifiers() & mod) != 0;
}
};
}
//
/** tries to resolve a java type name to a Class
* if optional {@link ClassLoader}s are not specified, then both {@link org.reflections.util.ClasspathHelper#contextClassLoader()} and {@link org.reflections.util.ClasspathHelper#staticClassLoader()} are used
* */
public static Class> forName(String typeName, ClassLoader... classLoaders) {
if (getPrimitiveNames().contains(typeName)) {
return getPrimitiveTypes().get(getPrimitiveNames().indexOf(typeName));
} else {
String type;
if (typeName.contains("[")) {
int i = typeName.indexOf("[");
type = typeName.substring(0, i);
String array = typeName.substring(i).replace("]", "");
if (getPrimitiveNames().contains(type)) {
type = getPrimitiveDescriptors().get(getPrimitiveNames().indexOf(type));
} else {
type = "L" + type + ";";
}
type = array + type;
} else {
type = typeName;
}
List reflectionsExceptions = Lists.newArrayList();
for (ClassLoader classLoader : ClasspathHelper.classLoaders(classLoaders)) {
if (type.contains("[")) {
try { return Class.forName(type, false, classLoader); }
catch (Throwable e) {
reflectionsExceptions.add(new ReflectionsException("could not get type for name " + typeName, e));
}
}
try { return classLoader.loadClass(type); }
catch (Throwable e) {
reflectionsExceptions.add(new ReflectionsException("could not get type for name " + typeName, e));
}
}
if (Reflections.log != null) {
for (ReflectionsException reflectionsException : reflectionsExceptions) {
Reflections.log.warn("could not get type for name " + typeName + " from any class loader",
reflectionsException);
}
}
return null;
}
}
/** try to resolve all given string representation of types to a list of java types */
public static List> forNames(final Iterable classes, ClassLoader... classLoaders) {
List> result = new ArrayList>();
for (String className : classes) {
Class> type = forName(className, classLoaders);
if (type != null) {
result.add((Class extends T>) type);
}
}
return result;
}
private static Class[] parameterTypes(Member member) {
return member != null ?
member.getClass() == Method.class ? ((Method) member).getParameterTypes() :
member.getClass() == Constructor.class ? ((Constructor) member).getParameterTypes() : null : null;
}
private static Set parameterAnnotations(Member member) {
Set result = Sets.newHashSet();
Annotation[][] annotations =
member instanceof Method ? ((Method) member).getParameterAnnotations() :
member instanceof Constructor ? ((Constructor) member).getParameterAnnotations() : null;
for (Annotation[] annotation : annotations) Collections.addAll(result, annotation);
return result;
}
private static Set> annotationTypes(Iterable annotations) {
Set> result = Sets.newHashSet();
for (Annotation annotation : annotations) result.add(annotation.annotationType());
return result;
}
private static Class extends Annotation>[] annotationTypes(Annotation[] annotations) {
Class extends Annotation>[] result = new Class[annotations.length];
for (int i = 0; i < annotations.length; i++) result[i] = annotations[i].annotationType();
return result;
}
//
private static List primitiveNames;
private static List primitiveTypes;
private static List primitiveDescriptors;
private static void initPrimitives() {
if (primitiveNames == null) {
primitiveNames = Lists.newArrayList("boolean", "char", "byte", "short", "int", "long", "float", "double", "void");
primitiveTypes = Lists.newArrayList(boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, void.class);
primitiveDescriptors = Lists.newArrayList("Z", "C", "B", "S", "I", "J", "F", "D", "V");
}
}
private static List getPrimitiveNames() { initPrimitives(); return primitiveNames; }
private static List getPrimitiveTypes() { initPrimitives(); return primitiveTypes; }
private static List getPrimitiveDescriptors() { initPrimitives(); return primitiveDescriptors; }
//
static Set filter(final T[] elements, Predicate super T>... predicates) {
return isEmpty(predicates) ? Sets.newHashSet(elements) :
Sets.newHashSet(Iterables.filter(Arrays.asList(elements), Predicates.and(predicates)));
}
static Set filter(final Iterable elements, Predicate super T>... predicates) {
return isEmpty(predicates) ? Sets.newHashSet(elements) :
Sets.newHashSet(Iterables.filter(elements, Predicates.and(predicates)));
}
private static boolean areAnnotationMembersMatching(Annotation annotation1, Annotation annotation2) {
if (annotation2 != null && annotation1.annotationType() == annotation2.annotationType()) {
for (Method method : annotation1.annotationType().getDeclaredMethods()) {
try {
if (!method.invoke(annotation1).equals(method.invoke(annotation2))) return false;
} catch (Exception e) {
throw new ReflectionsException(String.format("could not invoke method %s on annotation %s", method.getName(), annotation1.annotationType()), e);
}
}
return true;
}
return false;
}
}