A Java runtime metadata analysis, in the spirit of Scannotations
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.
Using Reflections you can query your metadata for:
- get all subtypes of some type
- get all types annotated with some annotation
- get all types annotated with some annotation, including annotation parameters matching
- get all methods annotated with some
How to use?
Use the one-stop-shop Reflections object for all that Reflections:
- Get an instance of a Reflections object, providing it with your preferred configuration
- Query your project's metadata
A simple example might be:
Configuration configuration = new AbstractConfiguration() {
{
setUrls(ClasspathHelper.getUrlsForCurrentClasspath());
setScanners(new SubTypesScanner(), new ClassAnnotationsScanner());
setFilter(new IncludeExcludeChain(
new IncludePrefix("your project's common package prefix here...")
));
}
};
Reflections reflections = new Reflections(configuration);
// get all subtypes of some type
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);
// get all types annotated with some annotation
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);
// get all types annotated with some annotation, including annotation parameters matching
Set<Class<?>> annotated1 = reflections.getTypesAnnotatedWith(new SomeAnnotation() {
public String value() {return "1";}
public Class<? extends Annotation> annotationType() {return SomeAnnotation.class;}
});
}You can use other scanners defined in Reflections as well, such as: SubTypesScanner, ClassAnnotationsScanner, FieldAnnotationsScanner, MethodAnnotationsScanner, ConvertersScanner. Than use the equivalent query method in the Reflections object.
Check out the tests here - with more examples on it's functionality
Reflections Maven plugin
There is the ReflectionsMojo Maven plugin available for your project. With simple configuration you can save all scanned metadata into xml files upon compiling. Later on, when your project is bootstrapping you can let Reflections collect all those resources and re-create that metadata for you, making it available at runtime without re-scanning the classpath - thus reducing the bootstrapping time.
Use this maven configuration in your pom file:
<build>
<plugins>
<plugin>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9 or whatever the version might be</version>
<executions>
<execution>
<goals>
<goal>reflections</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>Than use Reflections to collect these post compiled resources at runtime, without the need to scan and index classpath:
Reflections reflections = new Reflections(
ClasspathHelper.getUrlsForPackagePrefix("META-INF/reflections"),
new PatternFilter("META-INF/reflections/.*\\-reflections.xml"));By default, the Reflections Maven plugin saves the marshalled xml file of scanned metadata into ${project.build.outputDirectory}/META-INF/reflections/${project.artifactId}-reflections.xml
This way, you can dynamically collect all post compiled resources from your project's modules, without knowing of each other.
Check out in the wikis for the ReflectionsMojo documentation
Extending Reflections
You can easily extend Reflections by :
- create your specialized scan class, should extend AbstractScanner
- provide a query method within that scan class
- next, use that scanner instance to first configure Reflections and than to query
A use case for automatic registration of hibernate (annotation) mappings and the so
For Hibernate annotations, instead of maintaining the list of entities in a xml, use Reflections to automatically and transparently register entities.
Configuration configuration; //hibernate's configuration
...
for (Class<?> entity : reflections.getTypesAnnotatedWith(Entity.class)) {
configuration.addResource(entity.getName);
}A use case for a multi project module, with Guice DI
With some simple steps you can achieve a nice binding and bootstrapping solution:
- In your project's parent pom, configure ReflectionsMojo
- In your project's entry point, instantiate a Reflections object and:
- Collect all post compiled resources
- Get all classes of type com.google.inject.Module
- Aggregate all binding information into one binder and create your project's Injector
Next,
- find all methods annotated with, let's say @Bootstrap, and execute them.
Cheers