Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ronmamo/reflections
Java runtime metadata analysis
https://github.com/ronmamo/reflections
Last synced: 12 days ago
JSON representation
Java runtime metadata analysis
- Host: GitHub
- URL: https://github.com/ronmamo/reflections
- Owner: ronmamo
- License: wtfpl
- Created: 2013-04-16T16:19:26.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2024-06-17T21:43:09.000Z (5 months ago)
- Last Synced: 2024-10-29T19:19:57.446Z (13 days ago)
- Language: Java
- Homepage:
- Size: 1.01 MB
- Stars: 4,722
- Watchers: 189
- Forks: 701
- Open Issues: 120
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: COPYING.txt
Awesome Lists containing this project
- awesome-java - Reflections - Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project. (Projects / Introspection)
README
*❗ Please note: Reflections library is currently NOT under active development or maintenance ❗*
*Thank you for your continuous support!
There are open issues and also workarounds. Release version will be considered incase contributing PR fixing the main issues.**Last released `org.reflections:reflections:0.10.2` (Oct 2021)*
----
# Java runtime metadata analysis
[![Build Status](https://travis-ci.org/ronmamo/reflections.svg?branch=master)](https://travis-ci.org/ronmamo/reflections)
Reflections scans and indexes your project's classpath metadata, allowing reverse transitive query of the type system on runtime.
Using Reflections you can query for example:
* Subtypes of a type
* Types annotated with an annotation
* Methods with annotation, parameters, return type
* 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
# Mavenorg.reflections
reflections
0.10.2# Gradle
implementation 'org.reflections:reflections:0.10.2'
```Create Reflections instance and use the query functions:
```java
Reflections reflections = new Reflections("com.my.project");Set> subTypes =
reflections.get(SubTypes.of(SomeType.class).asClass());Set> annotated =
reflections.get(SubTypes.of(TypesAnnotated.with(SomeAnnotation.class)).asClass());
```Or using previous 0.9.x APIs, for example:
```java
Set> subTypes =
reflections.getSubTypesOf(SomeType.class);Set> annotated =
reflections.getTypesAnnotatedWith(SomeAnnotation.class);
```*Note that there are some breaking changes with Reflections 0.10+, along with performance improvements and more functional API, see below.*
### Scan
Creating Reflections instance requires [ConfigurationBuilder](https://ronmamo.github.io/reflections/org/reflections/util/ConfigurationBuilder.html), typically configured with packages and [Scanners](https://ronmamo.github.io/reflections/org/reflections/scanners/Scanners.html) to use:```java
// typical usage: scan package with the default scanners SubTypes, TypesAnnotated
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.forPackage("com.my.project")
.filterInputsBy(new FilterBuilder().includePackage("com.my.project")));
```Other examples:
```java
import static org.reflections.scanners.Scanners.*;// scan package with specific scanners
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.forPackage("com.my.project")
.filterInputsBy(new FilterBuilder().includePackage("com.my.project").excludePackage("com.my.project.exclude"))
.setScanners(TypesAnnotated, MethodsAnnotated, MethodsReturn));
```Note that:
* **Scanner must be configured in order to be queried, otherwise an empty result is returned**
If not specified, default scanners will be used SubTypes, TypesAnnotated.
For all standard scanners use `Scanners.values()`. See more scanners in the source [package](https://ronmamo.github.io/reflections/org/reflections/scanners).
* **All relevant URLs should be configured**
Consider `.filterInputsBy()` in case too many classes are scanned.
If required, Reflections will [expand super types](https://ronmamo.github.io/reflections/org/reflections/Reflections.html#expandSuperTypes(java.util.Map)) in order to get the transitive closure metadata without scanning large 3rd party urls.
* Classloader can optionally be used for resolving runtime classes from names.### Query
Once Reflections was instantiated and scanning was successful, it can be used for querying the indexed metadata.```java
import static org.reflections.scanners.Scanners.*;// SubTypes
Set> modules =
reflections.get(SubTypes.of(Module.class).asClass());// TypesAnnotated (*1)
Set> singletons =
reflections.get(TypesAnnotated.with(Singleton.class).asClass());// MethodsAnnotated
Set resources =
reflections.get(MethodsAnnotated.with(GetMapping.class).as(Method.class));// FieldsAnnotated
Set ids =
reflections.get(FieldsAnnotated.with(Id.class).as(Field.class));// Resources
Set properties =
reflections.get(Resources.with(".*\\.properties"));
```More scanners:
```java
// MethodsReturn
Set voidMethods =
reflections.get(MethodsReturn.with(void.class).as(Method.class));// MethodsSignature
Set someMethods =
reflections.get(MethodsSignature.of(long.class, int.class).as(Method.class));// MethodsParameter
Set pathParam =
reflections.get(MethodsParameter.of(PathParam.class).as(Method.class));// ConstructorsAnnotated
Set injectables =
reflections.get(ConstructorsAnnotated.with(Inject.class).as(Constructor.class));// ConstructorsSignature
Set someConstructors =
reflections.get(ConstructorsSignature.of(String.class).as(Constructor.class));// MethodParameterNamesScanner
List parameterNames =
reflections.getMemberParameterNames(member);// MemberUsageScanner
Set usages =
reflections.getMemberUsages(member)
```*See more examples in [ReflectionsQueryTest](src/test/java/org/reflections/ReflectionsQueryTest.java).*
*Note that previous 0.9.x APIs are still supported*
Compare Scanners and previous 0.9.x API (*)
| Scanners | previous 0.9.x API | previous Scanner |
| -------- | ------------------ | ------ |
| `get(SubType.of(T))` | getSubTypesOf(T) | ~~SubTypesScanner~~ |
| `get(SubTypes.of(`
`TypesAnnotated.with(A)))` | getTypesAnnotatedWith(A) *(1)*| ~~TypeAnnotationsScanner~~ |
| `get(MethodsAnnotated.with(A))` | getMethodsAnnotatedWith(A) | ~~MethodAnnotationsScanner~~ |
| `get(ConstructorsAnnotated.with(A))` | getConstructorsAnnotatedWith(A) *(2)*| ~~MethodAnnotationsScanner~~ |
| `get(FieldsAnnotated.with(A))` | getFieldsAnnotatedWith(A) | ~~FieldAnnotationsScanner~~ |
| `get(Resources.with(regex))` | getResources(regex) | ~~ResourcesScanner~~ |
| `get(MethodsParameter.with(P))` | getMethodsWithParameter(P) *(3)*
~~getMethodsWithAnyParamAnnotated(P)~~| ~~MethodParameterScanner~~
*obsolete* |
| `get(MethodsSignature.of(P, ...))` | getMethodsWithSignature(P, ...) *(3)
~~getMethodsMatchParams(P, ...)~~*| " |
| `get(MethodsReturn.of(T))` | getMethodsReturn(T) *(3)*| " |
| `get(ConstructorsParameter.with(P))` | getConstructorsWithParameter(P) *(3)
~~getConstructorsWithAnyParamAnnotated(P)~~*| " |
| `get(ConstructorsSignature.of(P, ...))` | getConstructorsWithSignature(P, ...) *(3)
~~getConstructorsMatchParams(P, ...)~~*| " |*Note: `asClass()` and `as()` mappings were omitted*
*(1): The equivalent of `getTypesAnnotatedWith(A)` is `get(SubTypes.of(TypesAnnotated.with(A)))`, including SubTypes*
*(2): MethodsAnnotatedScanner does not include constructor annotation scanning, use instead Scanners.ConstructorsAnnotated*
*(3): MethodParameterScanner is obsolete, use instead as required:
Scanners.MethodsParameter, Scanners.MethodsSignature, Scanners.MethodsReturn, Scanners.ConstructorsParameter, Scanners.ConstructorsSignature*## ReflectionUtils
Apart from scanning classpath metadata using [Javassist](https://github.com/jboss-javassist/javassist),
Java Reflection convenient methods are available using
[ReflectionsUtils](https://ronmamo.github.io/reflections/org/reflections/ReflectionUtils.html):```java
import static org.reflections.ReflectionUtils.*;Set> superTypes = get(SuperTypes.of(T));
Set fields = get(Fields.of(T));
Set constructors = get(Constructors.of(T));
Set methods = get(Methods.of(T));
Set resources = get(Resources.with(T));Set annotations = get(Annotations.of(T));
Set> annotationTypes = get(AnnotationTypes.of(T));
```*Previous ReflectionUtils 0.9.x API is still supported though marked for removal, more info in the javadocs.*
## Query API
Each Scanner and ReflectionUtils function implements [QueryBuilder](https://ronmamo.github.io/reflections/org/reflections/util/QueryBuilder.html), and supports:
* `get()` - function returns direct values
* `with()` or `of()` - function returns all transitive values*For example, `Scanners.SubTypes.get(T)` return direct subtypes,
while `Scanners.SubTypes.of(T)` return transitive subtypes hierarchy.
Same goes for `Scanners.TypesAnnotated` and `ReflectionUtils.SuperTypes` etc.*Next, each function implements [QueryFunction](https://ronmamo.github.io/reflections/org/reflections/util/QueryFunction.html),
and provides fluent functional interface for composing `filter()`, `map()`, `flatMap()`, `as()` and more, such that:```java
// filter, as/map
QueryFunction getters =
Methods.of(C1.class)
.filter(withModifier(Modifier.PUBLIC))
.filter(withPrefix("get").and(withParametersCount(0)))
.as(Method.class);// compose Scanners and ReflectionUtils functions
QueryFunction methods =
SubTypes.of(type).asClass() // <-- classpath scanned metadata
.flatMap(Methods::of); // <-- java reflection api// function of function
QueryFunction> queryAnnotations =
Annotations.of(Methods.of(C4.class))
.map(Annotation::annotationType);
```See more in [ReflectionUtilsQueryTest](https://github.com/ronmamo/reflections/tree/master/src/test/java/org/reflections/ReflectionUtilsQueryTest.java)
A more complex example demonstrates getting merged annotations of rest controllers endpoints:
```java
// get all annotations of RequestMapping hierarchy (GetMapping, PostMapping, ...)
Set> metaAnnotations =
reflections.get(TypesAnnotated.getAllIncluding(RequestMapping.class.getName()).asClass());QueryFunction> queryAnnotations =
// get all controller endpoint methods
MethodsAnnotated.with(metaAnnotations).as(Method.class)
.map(method ->
// get both method's + declaring class's RequestMapping annotations
get(Annotations.of(method.getDeclaringClass())
.add(Annotations.of(method))
.filter(a -> metaAnnotations.contains(a.annotationType())))
.stream()
// merge annotations' member values into a single hash map
.collect(new AnnotationMergeCollector(method)));// apply query and map merged hashmap into java annotation proxy
Set mergedAnnotations =
reflections.get(mergedAnnotation
.map(map -> ReflectionUtils.toAnnotation(map, metaAnnotation)));
```Check the [tests](src/test/java/org/reflections) folder for more examples and API usage
### What else?
- **Integrating with build lifecycle**
It is sometime useful to `Reflections.save()` the scanned metadata into xml/json as part of the build lifecycle for generating resources,
and then collect it on bootstrap with `Reflections.collect()` and avoid scanning. *See [reflections-maven](https://github.com/ronmamo/reflections-maven/) for example*.
- [JavaCodeSerializer](https://ronmamo.github.io/reflections/org/reflections/serializers/JavaCodeSerializer.html) - scanned metadata can be persisted into a generated Java source code.
Although less common, it can be useful for accessing types and members in a strongly typed manner. *(see [example](src/test/java/org/reflections/MyTestModelStore.java))*
- [AnnotationMergeCollector](https://ronmamo.github.io/reflections/org/reflections/util/AnnotationMergeCollector.html) - can be used to merge similar annotations. *(see [test](src/test/java/org/reflections/ReflectionUtilsQueryTest.java#L216))*
- `MemberUsageScanner` - experimental scanner allow querying for member usages `getMemberUsages()` of packages/types/elements in the classpath.
Can be used for finding usages between packages, layers, modules, types etc.----
*Spread the spirit of open-source and collaboration, clean code and simplicity*