Annotations-related helpers

This commit is contained in:
Emmanuel BENOîT 2015-09-12 11:13:32 +02:00
parent ea9563c324
commit d633aac37d

View file

@ -0,0 +1,200 @@
package info.ebenoit.ebul.reflection;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
/**
* Helpers to deal with annotated methods, fields or classes.
*
* @author <a href="mailto:ebenoit@ebenoit.info">E. Benoît</a>
*/
public final class Annotations
{
/**
* Finds all declared methods that have a specific annotation in a given class
*
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @return the list of methods that have the specified annotation
*/
public static final ArrayList< Method > findAnnotatedMethods( final Class< ? > target ,
final Class< ? extends Annotation > annotation )
{
final ArrayList< Method > methods = new ArrayList< >( );
Annotations.findAnnotatedMethods( methods , target , annotation );
return methods;
}
/**
* Finds all declared methods that have a specific annotation in a given class and adds them to an existing
* {@link Collection}.
*
* @param output
* the collection to which methods will be added
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @return the output collection
*/
public static final Collection< Method > findAnnotatedMethods( final Collection< Method > output ,
final Class< ? > target , final Class< ? extends Annotation > annotation )
{
for ( final Method m : target.getDeclaredMethods( ) ) {
if ( m.isAnnotationPresent( annotation ) ) {
output.add( m );
}
}
return output;
}
/**
* Finds all declared fields that have a specific annotation in a given class
*
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @return the list of fields that have the specified annotation
*/
public static final ArrayList< Field > findAnnotatedFields( final Class< ? > target ,
final Class< ? extends Annotation > annotation )
{
final ArrayList< Field > fields = new ArrayList< >( );
Annotations.findAnnotatedFields( fields , target , annotation );
return fields;
}
/**
* Finds all declared fields that have a specific annotation in a given class and adds them to an existing
* {@link Collection}.
*
* @param output
* the output collection
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @return the output collection
*/
public static final Collection< Field > findAnnotatedFields( final Collection< Field > output ,
final Class< ? > target , final Class< ? extends Annotation > annotation )
{
for ( final Field f : target.getDeclaredFields( ) ) {
if ( f.isAnnotationPresent( annotation ) ) {
output.add( f );
}
}
return output;
}
/**
* Applies a function to declared methods with a specific annotation
*
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @param function
* the function to apply to the methods
*/
public static final void applyToAnnotatedMethods( final Class< ? > target ,
final Class< ? extends Annotation > annotation , final Consumer< Method > function )
{
for ( final Method m : target.getDeclaredMethods( ) ) {
if ( m.isAnnotationPresent( annotation ) ) {
function.accept( m );
}
}
}
/**
* Applies a function to declared fields with a specific annotation
*
* @param target
* the class to examine
* @param annotation
* the annotation that must be present
* @param function
* the function to apply to the fields
*/
public static final void applyToAnnotatedFields( final Class< ? > target ,
final Class< ? extends Annotation > annotation , final Consumer< Field > function )
{
for ( final Field f : target.getDeclaredFields( ) ) {
if ( f.isAnnotationPresent( annotation ) ) {
function.accept( f );
}
}
}
/**
* Finds the closest class in a hierarchy that has the specified annotation.
* <p>
* For example, assuming class A extends B which extends C which extends D, both B and C having the annotation, this
* method will return B if called on A or B.
*
* @param klass
* the class to examine
* @param annotation
* the annotation to look for
* @return the closest class with the specified annotation in the hierarchy, or <code>null</code> if the annotation
* is not present.
*/
public static final < T > Class< ? super T > findClosestClass( final Class< T > klass ,
final Class< ? extends Annotation > annotation )
{
Class< ? super T > current = klass;
while ( current != null ) {
if ( current.isAnnotationPresent( annotation ) ) {
return current;
}
current = current.getSuperclass( );
}
return null;
}
/**
* Finds the farthest class in a hierarchy that has the specified annotation.
* <p>
* For example, assuming class A extends B which extends C which extends D, both B and C having the annotation, this
* method will return C if called on A or B.
*
* @param klass
* the class to examine
* @param annotation
* the annotation to look for
* @return the farthest class with the specified annotation in the hierarchy, or <code>null</code> if the annotation
* is not present.
*/
public static final < T > Class< ? super T > findFarthestClass( final Class< T > klass ,
final Class< ? extends Annotation > annotation )
{
Class< ? super T > found = null , current = klass;
while ( current != null ) {
if ( current.isAnnotationPresent( annotation ) ) {
found = current;
}
current = current.getSuperclass( );
}
return found;
}
}