Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find annotated methods in a given package?

I have a simple marker annotation for methods (similar to the first example in Item 35 in Effective Java (2nd ed)):

/**  * Marker annotation for methods that are called from installer's   * validation scripts etc.   */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InstallerMethod { } 

Then, in a given package (say com.acme.installer), which has a few subpackages containing some 20 classes, I'd like to find all methods that are annotated with it. (Because I'd like to do some checks regarding all the annotated methods in a unit test.)

What (if any) is the easiest way to do this? Preferably without adding new 3rd party libraries or frameworks.

Edit: to clarify, obviously method.isAnnotationPresent(InstallerMethod.class) will be the way to check if a method has the annotation - but this problem includes finding all the methods.

like image 860
Jonik Avatar asked May 14 '09 08:05

Jonik


People also ask

How do you check if a method has an annotation?

The isAnnotation() method is used to check whether a class object is an annotation. The isAnnotation() method has no parameters and returns a boolean value. If the return value is true , then the class object is an annotation. If the return value is false , then the class object is not an annotation.

How does spring find annotated classes?

Spring has something called a AnnotatedTypeScanner class. This class has the code for actual scanning of the classpath resources. It does this by using the class metadata available at runtime.

What is annotated method?

An annotation is a construct associated with Java source code elements such as classes, methods, and variables. Annotations provide information to a program at compile time or at runtime based on which the program can take further action.

How do I search annotations in eclipse?

Try: CTRL-H -> File Search, check Case Sensitive and Regular expression, and input: @[A-Z] for Containing text.


2 Answers

If you want to implement it yourself, these methods will find all the classes in a given package:

/**  * Scans all classes accessible from the context class loader which belong  * to the given package and subpackages.  *   * @param packageName  *            The base package  * @return The classes  * @throws ClassNotFoundException  * @throws IOException  */ private Iterable<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     String path = packageName.replace('.', '/');     Enumeration<URL> resources = classLoader.getResources(path);     List<File> dirs = new ArrayList<File>();     while (resources.hasMoreElements())     {         URL resource = resources.nextElement();         URI uri = new URI(resource.toString());         dirs.add(new File(uri.getPath()));     }     List<Class> classes = new ArrayList<Class>();     for (File directory : dirs)     {         classes.addAll(findClasses(directory, packageName));     }      return classes; }  /**  * Recursive method used to find all classes in a given directory and  * subdirs.  *   * @param directory  *            The base directory  * @param packageName  *            The package name for classes found inside the base directory  * @return The classes  * @throws ClassNotFoundException  */ private List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {     List<Class> classes = new ArrayList<Class>();     if (!directory.exists())     {         return classes;     }     File[] files = directory.listFiles();     for (File file : files)     {         if (file.isDirectory())         {             classes.addAll(findClasses(file, packageName + "." + file.getName()));         }         else if (file.getName().endsWith(".class"))         {             classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));         }     }     return classes; } 

Then you can just filter on those classes with the given annotation:

for (Method method : testClass.getMethods()) {     if (method.isAnnotationPresent(InstallerMethod.class))     {         // do something     } } 
like image 107
parkr Avatar answered Sep 22 '22 03:09

parkr


You should probably take a look at the open source Reflections library. With it you can easily achieve what you want with few lines of code:

Reflections reflections = new Reflections(      new ConfigurationBuilder().setUrls(      ClasspathHelper.forPackage( "com.acme.installer" ) ).setScanners(     new MethodAnnotationsScanner() ) ); Set<Method> methods = reflections.getMethodsAnnotatedWith(InstallerMethod.class); 
like image 29
Aleksander Blomskøld Avatar answered Sep 26 '22 03:09

Aleksander Blomskøld