package org.reflections;
import org.reflections.util.ClasspathHelper;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.reflections.util.Utils.filter;
convenient java reflection helper methods
1. some helper methods to get type by name: forName(String, ClassLoader...)
and forNames(Collection<String>, 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:
getAllSuperTypes(Class<?>, Predicate<? super Class<?>>...)
getAllFields(Class<?>, Predicate<? super Field>...)
getAllMethods(Class<?>, Predicate<? super Method>...)
getAllConstructors(Class<?>, Predicate<? super Constructor>...)
and predicates included here all starts with "with", such as
withAnnotation(Annotation)
withModifier(int)
withName(String)
withParameters(Class<?>[])
withAnyParameterAnnotation(Class<? extends Annotation>)
withParametersAssignableTo(Class[])
withParametersAssignableFrom(Class[])
withPrefix(String)
withReturnType(Class<Object>)
withType(Class<Object>)
withTypeAssignableTo
for example, getting all getters would be:
Set<Method> getters = getAllMethods(someClasses,
Predicates.and(
withModifier(Modifier.PUBLIC),
withPrefix("get"),
withParametersCount(0)));
/** convenient java reflection helper methods
* <p>
* 1. some helper methods to get type by name: {@link #forName(String, ClassLoader...)} and {@link #forNames(Collection, ClassLoader...)} )}
* <p>
* 2. some helper methods to get all types/methods/fields/constructors/properties matching some predicates, generally:
* <pre> Set<?> result = getAllXXX(type/s, withYYY) </pre>
* <p>where get methods are:
* <ul>
* <li>{@link #getAllSuperTypes(Class, java.util.function.Predicate...)}
* <li>{@link #getAllFields(Class, java.util.function.Predicate...)}
* <li>{@link #getAllMethods(Class, java.util.function.Predicate...)}
* <li>{@link #getAllConstructors(Class, java.util.function.Predicate...)}
* </ul>
* <p>and predicates included here all starts with "with", such as
* <ul>
* <li>{@link #withAnnotation(java.lang.annotation.Annotation)}
* <li>{@link #withModifier(int)}
* <li>{@link #withName(String)}
* <li>{@link #withParameters(Class[])}
* <li>{@link #withAnyParameterAnnotation(Class)}
* <li>{@link #withParametersAssignableTo(Class[])}
* <li>{@link #withParametersAssignableFrom(Class[])}
* <li>{@link #withPrefix(String)}
* <li>{@link #withReturnType(Class)}
* <li>{@link #withType(Class)}
* <li>{@link #withTypeAssignableTo}
* </ul>
*
* <p><br>
* for example, getting all getters would be:
* <pre>
* Set<Method> getters = getAllMethods(someClasses,
* Predicates.and(
* withModifier(Modifier.PUBLIC),
* withPrefix("get"),
* withParametersCount(0)));
* </pre>
* */
@SuppressWarnings("unchecked")
public abstract class ReflectionUtils {
would include Object.class
when getAllSuperTypes(Class<?>, Predicate<? super Class<?>>[])
. default is false. /** would include {@code Object.class} when {@link #getAllSuperTypes(Class, java.util.function.Predicate[])}. default is false. */
public static boolean includeObject = false;
get all super types of given type
, including, optionally filtered by predicates
include Object.class
if includeObject
is true
/** get all super types of given {@code type}, including, optionally filtered by {@code predicates}
* <p> include {@code Object.class} if {@link #includeObject} is true */
public static Set<Class<?>> getAllSuperTypes(final Class<?> type, Predicate<? super Class<?>>... predicates) {
Set<Class<?>> result = new LinkedHashSet<>();
if (type != null && (includeObject || !type.equals(Object.class))) {
result.add(type);
for (Class<?> supertype : getSuperTypes(type)) {
result.addAll(getAllSuperTypes(supertype));
}
}
return filter(result, predicates);
}
get the immediate supertype and interfaces of the given type
/** get the immediate supertype and interfaces of the given {@code type} */
public static Set<Class<?>> getSuperTypes(Class<?> type) {
Set<Class<?>> result = new LinkedHashSet<>();
Class<?> superclass = type.getSuperclass();
Class<?>[] interfaces = type.getInterfaces();
if (superclass != null && (includeObject || !superclass.equals(Object.class))) result.add(superclass);
if (interfaces != null && interfaces.length > 0) result.addAll(Arrays.asList(interfaces));
return result;
}
get all methods of given type
, up the super class hierarchy, optionally filtered by predicates
/** get all methods of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set<Method> getAllMethods(final Class<?> type, Predicate<? super Method>... predicates) {
Set<Method> result = new HashSet<>();
for (Class<?> t : getAllSuperTypes(type)) {
result.addAll(getMethods(t, predicates));
}
return result;
}
get methods of given type
, optionally filtered by predicates
/** get methods of given {@code type}, optionally filtered by {@code predicates} */
public static Set<Method> getMethods(Class<?> t, Predicate<? super Method>... predicates) {
return filter(t.isInterface() ? t.getMethods() : t.getDeclaredMethods(), predicates);
}
get all constructors of given type
, up the super class hierarchy, optionally filtered by predicates
/** get all constructors of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set<Constructor> getAllConstructors(final Class<?> type, Predicate<? super Constructor>... predicates) {
Set<Constructor> result = new HashSet<>();
for (Class<?> t : getAllSuperTypes(type)) {
result.addAll(getConstructors(t, predicates));
}
return result;
}
get constructors of given type
, optionally filtered by predicates
/** get constructors of given {@code type}, optionally filtered by {@code predicates} */
public static Set<Constructor> getConstructors(Class<?> t, Predicate<? super Constructor>... predicates) {
return filter(t.getDeclaredConstructors(), predicates);
}
get all fields of given type
, up the super class hierarchy, optionally filtered by predicates
/** get all fields of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static Set<Field> getAllFields(final Class<?> type, Predicate<? super Field>... predicates) {
Set<Field> result = new HashSet<>();
for (Class<?> t : getAllSuperTypes(type)) result.addAll(getFields(t, predicates));
return result;
}
get fields of given type
, optionally filtered by predicates
/** get fields of given {@code type}, optionally filtered by {@code predicates} */
public static Set<Field> getFields(Class<?> type, Predicate<? super Field>... predicates) {
return filter(type.getDeclaredFields(), predicates);
}
get all annotations of given type
, up the super class hierarchy, optionally filtered by predicates
/** get all annotations of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates} */
public static <T extends AnnotatedElement> Set<Annotation> getAllAnnotations(T type, Predicate<Annotation>... predicates) {
Set<Annotation> result = new HashSet<>();
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 type
, optionally honorInherited, optionally filtered by predicates
/** get annotations of given {@code type}, optionally honorInherited, optionally filtered by {@code predicates} */
public static <T extends AnnotatedElement> Set<Annotation> getAnnotations(T type, Predicate<Annotation>... predicates) {
return filter(type.getDeclaredAnnotations(), predicates);
}
filter all given elements
with predicates
, if given /** filter all given {@code elements} with {@code predicates}, if given */
public static <T extends AnnotatedElement> Set<T> getAll(final Set<T> elements, Predicate<? super T>... predicates) {
return filter(elements, predicates);
}
//predicates
where member name equals given name
/** where member name equals given {@code name} */
public static <T extends Member> Predicate<T> withName(final String name) {
return input -> input != null && input.getName().equals(name);
}
where member name startsWith given prefix
/** where member name startsWith given {@code prefix} */
public static <T extends Member> Predicate<T> withPrefix(final String prefix) {
return input -> input != null && input.getName().startsWith(prefix);
}
where member's toString
matches given regex
for example:
getAllMethods(someClass, withPattern("public void .*"))
/** where member's {@code toString} matches given {@code regex}
* <p>for example:
* <pre>
* getAllMethods(someClass, withPattern("public void .*"))
* </pre>
* */
public static <T extends AnnotatedElement> Predicate<T> withPattern(final String regex) {
return input -> Pattern.matches(regex, input.toString());
}
where element is annotated with given annotation
/** where element is annotated with given {@code annotation} */
public static <T extends AnnotatedElement> Predicate<T> withAnnotation(final Class<? extends Annotation> annotation) {
return input -> input != null && input.isAnnotationPresent(annotation);
}
where element is annotated with given annotations
/** where element is annotated with given {@code annotations} */
public static <T extends AnnotatedElement> Predicate<T> withAnnotations(final Class<? extends Annotation>... annotations) {
return input -> input != null && Arrays.equals(annotations, annotationTypes(input.getAnnotations()));
}
where element is annotated with given annotation
, including member matching /** where element is annotated with given {@code annotation}, including member matching */
public static <T extends AnnotatedElement> Predicate<T> withAnnotation(final Annotation annotation) {
return input -> input != null && input.isAnnotationPresent(annotation.annotationType()) &&
areAnnotationMembersMatching(input.getAnnotation(annotation.annotationType()), annotation);
}
where element is annotated with given annotations
, including member matching /** where element is annotated with given {@code annotations}, including member matching */
public static <T extends AnnotatedElement> Predicate<T> withAnnotations(final Annotation... annotations) {
return input -> {
if (input != null) {
Annotation[] inputAnnotations = input.getAnnotations();
if (inputAnnotations.length == annotations.length) {
return IntStream.range(0, inputAnnotations.length)
.allMatch(i -> areAnnotationMembersMatching(inputAnnotations[i], annotations[i]));
}
}
return true;
};
}
when method/constructor parameter types equals given types
/** when method/constructor parameter types equals given {@code types} */
public static Predicate<Member> withParameters(final Class<?>... types) {
return input -> Arrays.equals(parameterTypes(input), types);
}
when member parameter types assignable to given types
/** when member parameter types assignable to given {@code types} */
public static Predicate<Member> withParametersAssignableTo(final Class... types) {
return input -> isAssignable(types, parameterTypes(input));
}
when method/constructor parameter types assignable from given types
/** when method/constructor parameter types assignable from given {@code types} */
public static Predicate<Member> withParametersAssignableFrom(final Class... types) {
return input -> isAssignable(parameterTypes(input), types);
}
when method/constructor parameters count equal given count
/** when method/constructor parameters count equal given {@code count} */
public static Predicate<Member> withParametersCount(final int count) {
return input -> input != null && parameterTypes(input).length == count;
}
when method/constructor has any parameter with an annotation matches given annotations
/** when method/constructor has any parameter with an annotation matches given {@code annotations} */
public static Predicate<Member> withAnyParameterAnnotation(final Class<? extends Annotation> annotationClass) {
return input -> input != null && annotationTypes(parameterAnnotations(input)).stream().anyMatch(input1 -> input1.equals(annotationClass));
}
when method/constructor has any parameter with an annotation matches given annotations
, including member matching /** when method/constructor has any parameter with an annotation matches given {@code annotations}, including member matching */
public static Predicate<Member> withAnyParameterAnnotation(final Annotation annotation) {
return input -> input != null && parameterAnnotations(input).stream().anyMatch(input1 -> areAnnotationMembersMatching(annotation, input1));
}
when field type equal given type
/** when field type equal given {@code type} */
public static <T> Predicate<Field> withType(final Class<T> type) {
return input -> input != null && input.getType().equals(type);
}
when field type assignable to given type
/** when field type assignable to given {@code type} */
public static <T> Predicate<Field> withTypeAssignableTo(final Class<T> type) {
return input -> input != null && type.isAssignableFrom(input.getType());
}
when method return type equal given type
/** when method return type equal given {@code type} */
public static <T> Predicate<Method> withReturnType(final Class<T> type) {
return input -> input != null && input.getReturnType().equals(type);
}
when method return type assignable from given type
/** when method return type assignable from given {@code type} */
public static <T> Predicate<Method> withReturnTypeAssignableTo(final Class<T> type) {
return input -> input != null && type.isAssignableFrom(input.getReturnType());
}
when member modifier matches given mod
for example:
withModifier(Modifier.PUBLIC)
/** when member modifier matches given {@code mod}
* <p>for example:
* <pre>
* withModifier(Modifier.PUBLIC)
* </pre>
*/
public static <T extends Member> Predicate<T> withModifier(final int mod) {
return input -> input != null && (input.getModifiers() & mod) != 0;
}
when class modifier matches given mod
for example:
withModifier(Modifier.PUBLIC)
/** when class modifier matches given {@code mod}
* <p>for example:
* <pre>
* withModifier(Modifier.PUBLIC)
* </pre>
*/
public static Predicate<Class<?>> withClassModifier(final int mod) {
return input -> input != null && (input.getModifiers() & mod) != 0;
}
//
tries to resolve a java type name to a Class
if optional ClassLoader
s are not specified, then both ClasspathHelper.contextClassLoader()
and ClasspathHelper.staticClassLoader()
are used
/** tries to resolve a java type name to a Class
* <p>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<ReflectionsException> reflectionsExceptions = new ArrayList<>();
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 /** try to resolve all given string representation of types to a list of java types */
public static <T> Set<Class<? extends T>> forNames(final Collection<String> classes, ClassLoader... classLoaders) {
return classes.stream()
.map(className -> (Class<? extends T>) forName(className, classLoaders))
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
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<Annotation> parameterAnnotations(Member member) {
Annotation[][] annotations =
member instanceof Method ? ((Method) member).getParameterAnnotations() :
member instanceof Constructor ? ((Constructor) member).getParameterAnnotations() : null;
return Arrays.stream(annotations).flatMap(Arrays::stream).collect(Collectors.toSet());
}
private static Set<Class<? extends Annotation>> annotationTypes(Collection<Annotation> annotations) {
return annotations.stream().map(Annotation::annotationType).collect(Collectors.toSet());
}
private static Class<? extends Annotation>[] annotationTypes(Annotation[] annotations) {
return Arrays.stream(annotations).map(Annotation::annotationType).toArray(Class[]::new);
}
//
private static List<String> primitiveNames;
private static List<Class> primitiveTypes;
private static List<String> primitiveDescriptors;
private static void initPrimitives() {
if (primitiveNames == null) {
primitiveNames = Arrays.asList("boolean", "char", "byte", "short", "int", "long", "float", "double", "void");
primitiveTypes = Arrays.asList(boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, void.class);
primitiveDescriptors = Arrays.asList("Z", "C", "B", "S", "I", "J", "F", "D", "V");
}
}
private static List<String> getPrimitiveNames() { initPrimitives(); return primitiveNames; }
private static List<Class> getPrimitiveTypes() { initPrimitives(); return primitiveTypes; }
private static List<String> getPrimitiveDescriptors() { initPrimitives(); return primitiveDescriptors; }
//
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;
}
private static boolean isAssignable(Class[] childClasses, Class[] parentClasses) {
if (childClasses == null) {
return parentClasses == null || parentClasses.length == 0;
}
if (childClasses.length != parentClasses.length) {
return false;
}
return IntStream.range(0, childClasses.length)
.noneMatch(i -> !parentClasses[i].isAssignableFrom(childClasses[i]) ||
parentClasses[i] == Object.class && childClasses[i] != Object.class);
}
}