{@code Set> supertypes = get(SuperTypes.of(type)) + * utils for querying java reflection meta types + * see {@link #SuperTypes}, {@link #Annotations}, {@link #AnnotationTypes}, {@link #Methods}, {@link #Constructors} and {@link #Fields}. + *
{@code + * Set- *> supertypes = get(SuperTypes.of(type)) * Set annotations = get(Annotations.of(type)) * } generally, apply {@link #get(QueryFunction)} on {@link QueryFunction} created by {@link UtilQueryBuilder}, and optionally use the functional methods in QueryFunction + *
generally, apply {@link #get(QueryFunction)} on {@link QueryFunction} created by {@link UtilQueryBuilder}, and optionally use the functional methods in QueryFunction. *
{@code get(Methods.of(type) * .filter(withPublic().and(withPrefix("get")).and(withParameterCount(0))) * .as(Method.class) diff --git a/src/main/java/org/reflections/Reflections.java b/src/main/java/org/reflections/Reflections.java index 3a297077..71d39d07 100644 --- a/src/main/java/org/reflections/Reflections.java +++ b/src/main/java/org/reflections/Reflections.java @@ -64,7 +64,8 @@ * * *Create Reflections instance, preferably using {@link ConfigurationBuilder}: - *
{@code Reflections reflections = new Reflections( + *{@code + * Reflections reflections = new Reflections( * new ConfigurationBuilder() * .forPackage("com.my.project")); * @@ -87,7 +88,8 @@ *Classloader can optionally be used for resolving runtime classes from names. * *
Query using {@link Reflections#get(QueryFunction)}, such as: - *{@code Set> modules = reflections.get(SubTypes.of(Module.class).asClass()); + * {@code + * Set> modules = reflections.get(SubTypes.of(Module.class).asClass()); * Set > singletons = reflections.get(TypesAnnotated.with(Singleton.class).asClass()); * Set properties = reflections.get(Resources.with(".*\\.properties")); * Set requests = reflections.get(MethodsAnnotated.with(RequestMapping.class).as(Method.class)); diff --git a/src/main/java/org/reflections/scanners/Scanners.java b/src/main/java/org/reflections/scanners/Scanners.java index b47d88aa..37b0eb9e 100644 --- a/src/main/java/org/reflections/scanners/Scanners.java +++ b/src/main/java/org/reflections/scanners/Scanners.java @@ -27,10 +27,13 @@ * {@link #SubTypes} *{@link #TypesAnnotated} *{@link #MethodsAnnotated} + *{@link #ConstructorsAnnotated} *{@link #FieldsAnnotated} *{@link #Resources} *{@link #MethodsParameter} + *{@link #ConstructorsParameter} *{@link #MethodsSignature} + *{@link #ConstructorsSignature} *{@link #MethodsReturn} * * note that scanners must be configured in {@link org.reflections.Configuration} in order to be queried diff --git a/src/main/java/org/reflections/util/JavassistHelper.java b/src/main/java/org/reflections/util/JavassistHelper.java index e3a71e3a..ac04bfc1 100644 --- a/src/main/java/org/reflections/util/JavassistHelper.java +++ b/src/main/java/org/reflections/util/JavassistHelper.java @@ -11,7 +11,6 @@ import javassist.bytecode.annotation.Annotation; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Function; @@ -22,12 +21,6 @@ public class JavassistHelper { /** setting this static to false will result in returning only {@link java.lang.annotation.RetentionPolicy#RUNTIME} visible annotation */ public static boolean includeInvisibleTag = true; - public static ListgetAnnotations(Function function) { - List list = getAnnotations((AnnotationsAttribute) function.apply(AnnotationsAttribute.visibleTag)); - if (includeInvisibleTag) list.addAll(getAnnotations((AnnotationsAttribute) function.apply(AnnotationsAttribute.invisibleTag))); - return list; - } - public static String fieldName(ClassFile classFile, FieldInfo object) { return String.format("%s.%s", classFile.getName(), object.getName()); } @@ -70,22 +63,39 @@ public static String getReturnType(MethodInfo method) { return Descriptor.toString(descriptor); } - public static List > getParametersAnnotations(MethodInfo method) { - List
> list = getAnnotations((ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.visibleTag)); - if (includeInvisibleTag) list.addAll(getAnnotations((ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.invisibleTag))); - return list; - } + public static List
getAnnotations(Function function) { + Function > names = function + .andThen(attribute -> attribute != null ? ((AnnotationsAttribute) attribute).getAnnotations() : null) + .andThen(JavassistHelper::annotationNames); - private static List > getAnnotations(ParameterAnnotationsAttribute attribute) { - return mapList(attribute, ParameterAnnotationsAttribute::getAnnotations, aa -> mapList(aa, a -> a, Annotation::getTypeName)); + List
result = new ArrayList<>(names.apply(AnnotationsAttribute.visibleTag)); + if (includeInvisibleTag) result.addAll(names.apply(AnnotationsAttribute.invisibleTag)); + return result; } - private static List getAnnotations(AnnotationsAttribute attribute) { - return mapList(attribute, AnnotationsAttribute::getAnnotations, Annotation::getTypeName); + public static List > getParametersAnnotations(MethodInfo method) { + Function
>> names = ((Function ) method::getAttribute) + .andThen(attribute -> attribute != null ? ((ParameterAnnotationsAttribute) attribute).getAnnotations() : null) + .andThen((Annotation[][] aa) -> aa != null ? Stream.of(aa).map(JavassistHelper::annotationNames).collect(Collectors.toList()) : Collections.emptyList()); + + List > visibleAnnotations = names.apply(ParameterAnnotationsAttribute.visibleTag); + if (!includeInvisibleTag) return new ArrayList<>(visibleAnnotations); + + List
> invisibleAnnotations = names.apply(ParameterAnnotationsAttribute.invisibleTag); + if (invisibleAnnotations.isEmpty()) return new ArrayList<>(visibleAnnotations); + + // horror + List
> result = new ArrayList<>(); + for (int i = 0; i < Math.max(visibleAnnotations.size(), invisibleAnnotations.size()); i++) { + List
concat = new ArrayList<>(); + if (i < visibleAnnotations.size()) concat.addAll(visibleAnnotations.get(i)); + if (i < invisibleAnnotations.size()) concat.addAll(invisibleAnnotations.get(i)); + result.add(concat); + } + return result; } - // todo inline & simplify - private static List mapList(T t, Function f1, Function f2) { - return t != null ? Arrays.stream(f1.apply(t)).map(f2).collect(Collectors.toList()) : Collections.emptyList(); + private static List annotationNames(Annotation[] annotations) { + return annotations != null ? Stream.of(annotations).map(Annotation::getTypeName).collect(Collectors.toList()) : Collections.emptyList(); } } diff --git a/src/main/java/org/reflections/util/ReflectionUtilsPredicates.java b/src/main/java/org/reflections/util/ReflectionUtilsPredicates.java index cc83aee8..f5603b3f 100644 --- a/src/main/java/org/reflections/util/ReflectionUtilsPredicates.java +++ b/src/main/java/org/reflections/util/ReflectionUtilsPredicates.java @@ -34,6 +34,13 @@ public static Predicate withPrefix(final String prefix) { return input -> input != null && input.getName().startsWith(prefix); } + /** + * where annotated element name startsWith given {@code prefix} + */ + public static Predicate withNamePrefix(final String prefix) { + return input -> toName(input).startsWith(prefix); + } + /** * where member's {@code toString} matches given {@code regex} * get(Methods.of(someClass).filter(withPattern("public void .*")))@@ -200,6 +207,14 @@ public static boolean isAssignable(Class[] childClasses, Class[] parentClasses) } // + private static String toName(Object input) { + return input == null ? "" : + input.getClass().equals(Class.class) ? ((Class>) input).getName() : + input instanceof Member ? ((Member) input).getName() : + input instanceof Annotation ? ((Annotation) input).annotationType().getName() : + input.toString(); + } + private static Class[] parameterTypes(Member member) { return member != null ? member.getClass() == Method.class ? ((Method) member).getParameterTypes() : diff --git a/src/test/java/org/reflections/MyTestModelStore.java b/src/test/java/org/reflections/MyTestModelStore.java index 3ea7b834..1c7126df 100644 --- a/src/test/java/org/reflections/MyTestModelStore.java +++ b/src/test/java/org/reflections/MyTestModelStore.java @@ -36,6 +36,8 @@ interface methods { interface value {} } } + interface TestModel$AM2 { + } interface TestModel$C1 { interface annotations { interface org_reflections_TestModel$AC1 {} diff --git a/src/test/java/org/reflections/ReflectionUtilsQueryTest.java b/src/test/java/org/reflections/ReflectionUtilsQueryTest.java index 33e3f47c..7c8708d6 100644 --- a/src/test/java/org/reflections/ReflectionUtilsQueryTest.java +++ b/src/test/java/org/reflections/ReflectionUtilsQueryTest.java @@ -124,11 +124,9 @@ public void testMembers() throws NoSuchMethodException, NoSuchFieldException { @Test public void nestedQuery() { Set> annotations = - get(Annotations.of( + get(AnnotationTypes.of( Methods.of(C4.class)) - .map(Annotation::annotationType) - .filter(a -> !a.getName().startsWith("java.")) - .as()); + .filter(withNamePrefix("org.reflections"))); assertThat(annotations, equalTo(AM1.class)); @@ -198,6 +196,7 @@ public void annotationToMap() { Set