Skip to content

Commit

Permalink
0.10.1 - fix exception in JavassistHelper.getParametersAnnotations, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ronma committed Oct 6, 2021
1 parent ee52a9d commit eadb726
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 38 deletions.
16 changes: 10 additions & 6 deletions README.md
@@ -1,9 +1,9 @@
*Released `org.reflections:reflections:0.10`*
*Released `org.reflections:reflections:0.10.1`*

*Reflections library has ~4 million downloads per month from Maven Central, and is being used by thousands of [projects](https://github.com/ronmamo/reflections/network/dependents) and [libraries](https://mvnrepository.com/artifact/org.reflections/reflections/usages).
Thank you for your continuous support! And apologize for the issues. We're looking for community collaborators to assist in reviewing pull requests and issues, please reach out.*

# Java runtime metadata analysis, in the spirit of [Scannotations](http://bill.burkecentral.com/2008/01/14/scanning-java-annotations-at-runtime/)
# Java runtime metadata analysis

[![Build Status](https://travis-ci.org/ronmamo/reflections.svg?branch=master)](https://travis-ci.org/ronmamo/reflections)

Expand All @@ -16,18 +16,20 @@ Using Reflections you can query for example:
* Resources found in classpath
And more...

*Reflections was written in the spirit of [Scannotations](http://bill.burkecentral.com/2008/01/14/scanning-java-annotations-at-runtime/) library*

## Usage
Add Reflections dependency to your project:
```xml
# Maven
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10</version>
<version>0.10.1</version>
</dependency>

# Gradle
implementation 'org.reflections:reflections:0.10'
implementation 'org.reflections:reflections:0.10.1'
```

Create Reflections instance and use the query functions:
Expand All @@ -41,7 +43,7 @@ Set<Class<?>> annotated =
reflections.get(TypesAnnotated.with(SomeAnnotation.class).asClass());
```

*Note that there are some breaking changes with Reflections 0.10, along with performance improvements and more functional API. Migration is encouraged and should be easy though.*
*Note that there are some breaking changes with Reflections 0.10+, along with performance improvements and more functional API. Migration is encouraged and should be easy though.*

### Scan
Creating Reflections instance requires providing scanning configuration:
Expand Down Expand Up @@ -263,7 +265,9 @@ Although less common, it can be useful for accessing types and members in a stro
Can be used for finding usages between packages, layers, modules, types etc.

### Contribute
Pull requests are welcomed!!
Pull requests are welcomed!!
Here are some issues labeled with [please contribute :heart:](https://github.com/ronmamo/reflections/issues?q=is%3Aissue+is%3Aopen+label%3A%22please+contribute+%E2%9D%A4%EF%B8%8F%22+label%3A%22good+first+issue%22)
*We're looking for community collaborators to assist in reviewing pull requests and issues, please reach out.*

Dual licenced with Apache 2 and [WTFPL](http://www.wtfpl.net/), just do what the fuck you want to.

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -4,7 +4,7 @@

<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.11-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Reflections</name>
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/org/reflections/ReflectionUtils.java
Expand Up @@ -23,11 +23,13 @@
import static java.util.stream.Collectors.toList;

/**
* utils for querying java reflection meta types {@link #SuperTypes}, {@link #Annotations}, {@link #AnnotationTypes}, {@link #Methods}, {@link #Constructors}, {@link #Fields}.
* <pre>{@code Set<Class<?>> supertypes = get(SuperTypes.of(type))
* utils for querying java reflection meta types
* <p>see {@link #SuperTypes}, {@link #Annotations}, {@link #AnnotationTypes}, {@link #Methods}, {@link #Constructors} and {@link #Fields}.
* <pre>{@code
* Set<Class<?>> supertypes = get(SuperTypes.of(type))
* Set<Annotation> annotations = get(Annotations.of(type))
* }</pre>
* <p>generally, apply {@link #get(QueryFunction)} on {@link QueryFunction} created by {@link UtilQueryBuilder}, and optionally use the functional methods in QueryFunction
* <p>generally, apply {@link #get(QueryFunction)} on {@link QueryFunction} created by {@link UtilQueryBuilder}, and optionally use the functional methods in QueryFunction.
* <pre>{@code get(Methods.of(type)
* .filter(withPublic().and(withPrefix("get")).and(withParameterCount(0)))
* .as(Method.class)
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/org/reflections/Reflections.java
Expand Up @@ -64,7 +64,8 @@
* </ul>
*
* <p>Create Reflections instance, preferably using {@link ConfigurationBuilder}:
* <pre>{@code Reflections reflections = new Reflections(
* <pre>{@code
* Reflections reflections = new Reflections(
* new ConfigurationBuilder()
* .forPackage("com.my.project"));
*
Expand All @@ -87,7 +88,8 @@
* <p>Classloader can optionally be used for resolving runtime classes from names.
*
* <p></p>Query using {@link Reflections#get(QueryFunction)}, such as:
* <pre>{@code Set<Class<?>> modules = reflections.get(SubTypes.of(Module.class).asClass());
* <pre>{@code
* Set<Class<?>> modules = reflections.get(SubTypes.of(Module.class).asClass());
* Set<Class<?>> singletons = reflections.get(TypesAnnotated.with(Singleton.class).asClass());
* Set<String> properties = reflections.get(Resources.with(".*\\.properties"));
* Set<Method> requests = reflections.get(MethodsAnnotated.with(RequestMapping.class).as(Method.class));
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/reflections/scanners/Scanners.java
Expand Up @@ -27,10 +27,13 @@
* <li>{@link #SubTypes}</li>
* <li>{@link #TypesAnnotated}</li>
* <li>{@link #MethodsAnnotated}</li>
* <li>{@link #ConstructorsAnnotated}</li>
* <li>{@link #FieldsAnnotated}</li>
* <li>{@link #Resources}</li>
* <li>{@link #MethodsParameter}</li>
* <li>{@link #ConstructorsParameter}</li>
* <li>{@link #MethodsSignature}</li>
* <li>{@link #ConstructorsSignature}</li>
* <li>{@link #MethodsReturn}</li>
* </ul>
* <i>note that scanners must be configured in {@link org.reflections.Configuration} in order to be queried</i>
Expand Down
48 changes: 29 additions & 19 deletions src/main/java/org/reflections/util/JavassistHelper.java
Expand Up @@ -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;
Expand All @@ -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 List<String> getAnnotations(Function<String, AttributeInfo> function) {
List<String> 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());
}
Expand Down Expand Up @@ -70,22 +63,39 @@ public static String getReturnType(MethodInfo method) {
return Descriptor.toString(descriptor);
}

public static List<List<String>> getParametersAnnotations(MethodInfo method) {
List<List<String>> list = getAnnotations((ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.visibleTag));
if (includeInvisibleTag) list.addAll(getAnnotations((ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.invisibleTag)));
return list;
}
public static List<String> getAnnotations(Function<String, AttributeInfo> function) {
Function<String, List<String>> names = function
.andThen(attribute -> attribute != null ? ((AnnotationsAttribute) attribute).getAnnotations() : null)
.andThen(JavassistHelper::annotationNames);

private static List<List<String>> getAnnotations(ParameterAnnotationsAttribute attribute) {
return mapList(attribute, ParameterAnnotationsAttribute::getAnnotations, aa -> mapList(aa, a -> a, Annotation::getTypeName));
List<String> result = new ArrayList<>(names.apply(AnnotationsAttribute.visibleTag));
if (includeInvisibleTag) result.addAll(names.apply(AnnotationsAttribute.invisibleTag));
return result;
}

private static List<String> getAnnotations(AnnotationsAttribute attribute) {
return mapList(attribute, AnnotationsAttribute::getAnnotations, Annotation::getTypeName);
public static List<List<String>> getParametersAnnotations(MethodInfo method) {
Function<String, List<List<String>>> names = ((Function<String, AttributeInfo>) 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<List<String>> visibleAnnotations = names.apply(ParameterAnnotationsAttribute.visibleTag);
if (!includeInvisibleTag) return new ArrayList<>(visibleAnnotations);

List<List<String>> invisibleAnnotations = names.apply(ParameterAnnotationsAttribute.invisibleTag);
if (invisibleAnnotations.isEmpty()) return new ArrayList<>(visibleAnnotations);

// horror
List<List<String>> result = new ArrayList<>();
for (int i = 0; i < Math.max(visibleAnnotations.size(), invisibleAnnotations.size()); i++) {
List<String> 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 <T, A, R> List<R> mapList(T t, Function<T, A[]> f1, Function<A, R> f2) {
return t != null ? Arrays.stream(f1.apply(t)).map(f2).collect(Collectors.toList()) : Collections.emptyList();
private static List<String> annotationNames(Annotation[] annotations) {
return annotations != null ? Stream.of(annotations).map(Annotation::getTypeName).collect(Collectors.toList()) : Collections.emptyList();
}
}
2 changes: 2 additions & 0 deletions src/test/java/org/reflections/MyTestModelStore.java
Expand Up @@ -36,6 +36,8 @@ interface methods {
interface value {}
}
}
interface TestModel$AM2 {
}
interface TestModel$C1 {
interface annotations {
interface org_reflections_TestModel$AC1 {}
Expand Down
15 changes: 13 additions & 2 deletions src/test/java/org/reflections/ReflectionsQueryTest.java
Expand Up @@ -92,6 +92,10 @@ public void testTypesAnnotatedWithMemberMatching() {
reflections.get(TypesAnnotated.with(AC2.class).asClass()),
equalTo(C2.class, C3.class, I3.class, AC3.class, C7.class));

assertThat("direct types annotated with annotation with Retention(CLASS)",
reflections.get(TypesAnnotated.get(AC3.class).asClass()),
equalTo(C7.class));

assertThat("transitive subtypes of types annotated with annotation",
reflections.get(SubTypes.of(TypesAnnotated.with(AC2.class)).asClass()),
equalTo(C2.class, C3.class, I3.class, AC3.class, C7.class, C5.class, C6.class));
Expand Down Expand Up @@ -221,7 +225,8 @@ public void testMethods() throws NoSuchMethodException {

assertThat("methods with return type void",
reflections.get(MethodsReturn.of(void.class)),
equalToNames(C4.class.getDeclaredMethod("m1"),
equalToNames(
C4.class.getDeclaredMethod("m1"),
C4.class.getDeclaredMethod("m1", int.class, String[].class),
C4.class.getDeclaredMethod("m1", int[][].class, String[][].class)));

Expand All @@ -241,6 +246,12 @@ public Class<? extends Annotation> annotationType() {
assertThat("methods with parameter annotation filter by member matching",
reflections.get(MethodsParameter.with(AM1.class).as(Method.class).filter(withAnyParameterAnnotation(am1))),
equalTo(C4.class.getDeclaredMethod("m4", String.class)));

assertThat("methods with parameter annotation visible/invisible",
reflections.get(MethodsParameter.with(AM2.class)),
equalToNames(
C4.class.getDeclaredMethod("m4", String.class),
C4.class.getDeclaredMethod("m1", int.class, String[].class)));
}

@Test
Expand Down Expand Up @@ -308,7 +319,7 @@ public void testGetAll() {
equalTo("java.lang.Object", "java.lang.annotation.Annotation",
"org.reflections.TestModel$MAI1", "org.reflections.TestModel$AI1", "org.reflections.TestModel$AI2",
"org.reflections.TestModel$I1", "org.reflections.TestModel$I2", "org.reflections.TestModel$I3",
"org.reflections.TestModel$AF1", "org.reflections.TestModel$AM1",
"org.reflections.TestModel$AF1", "org.reflections.TestModel$AM1", "org.reflections.TestModel$AM2",
"org.reflections.TestModel$AC1", "org.reflections.TestModel$AC1n", "org.reflections.TestModel$AC2", "org.reflections.TestModel$AC3",
"org.reflections.TestModel$C1", "org.reflections.TestModel$C2", "org.reflections.TestModel$C3", "org.reflections.TestModel$C4",
"org.reflections.TestModel$C5", "org.reflections.TestModel$C6", "org.reflections.TestModel$C7"));
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/org/reflections/ReflectionsTest.java
Expand Up @@ -158,6 +158,10 @@ public void testMethodParameter() throws NoSuchMethodException {

assertThat(reflections.getMethodsWithParameter(AM1.class),
are(C4.class.getDeclaredMethod("m4", String.class)));

assertThat(reflections.getMethodsWithParameter(AM2.class),
are(C4.class.getDeclaredMethod("m4", String.class),
C4.class.getDeclaredMethod("m1", int.class, String[].class)));
}

@Test
Expand Down
10 changes: 5 additions & 5 deletions src/test/java/org/reflections/TestModel.java
Expand Up @@ -3,7 +3,7 @@
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.RetentionPolicy.*;

@SuppressWarnings({"ALL"})
public interface TestModel {
Expand All @@ -26,6 +26,7 @@ public interface TestModel {
public @Retention(RUNTIME) @interface AM1 {
public abstract String value();
}
public @interface AM2 {}
public @Retention(RUNTIME) @interface AF1 {
public abstract String value();
}
Expand All @@ -38,10 +39,10 @@ public C4() { }
@AM1("1") public C4(@AM1("1") String f1) { this.f1 = f1; }

@AM1("1") protected void m1() {}
@AM1("1") public void m1(int integer, String... strings) {}
@AM1("1") public void m1(int integer, @AM2 String... strings) {}
@AM1("1") public void m1(int[][] integer, String[][] strings) {}
@AM1("2") public String m3() {return null;}
public String m4(@AM1("2") String string) {return null;}
public String m4(@AM1("2") @AM2 String string) {return null;}
public C3 c2toC3(C2 c2) {return null;}
public int add(int i1, int i2) { return i1+i2; }
}
Expand All @@ -50,7 +51,6 @@ public class C5 extends C3 {}
public @AC2("ac2") interface I3 {}
public class C6 implements I3 {}

public @Retention(RUNTIME) @AC2("ac2") @interface AC3 { }
public @AC2("ac2") @interface AC3 { } // not @Retention(RUNTIME)
public @AC3 class C7 {}

}

0 comments on commit eadb726

Please sign in to comment.