13

I started a "for fun, nobody knows, nobody cares" open source project (LinkSet).

In one place I need to get an annotated method of a class.

Is there a more efficient way to do it than this? I mean without the need of iterating through every method?

for (final Method method : cls.getDeclaredMethods()) {

    final HandlerMethod handler = method.getAnnotation(HandlerMethod.class);
        if (handler != null) {
                return method;
          }
        }
Kevin
  • 30,111
  • 9
  • 76
  • 83
Łukasz Bownik
  • 6,149
  • 12
  • 42
  • 60
  • 1
    If you only want to know if the method has the annotation and don't care about the content of the annotation you can call `method.isAnnotationPresent(HandlerMethod.class)` – Geoff Reedy Feb 10 '10 at 14:26

3 Answers3

15

Take a look for Reflections (dependencies: Guava and Javassist). It's a library which has already optimized the most of it all. There's a Reflections#getMethodsAnnotatedWith() which suits your functional requirement.

Here's an SSCCE, just copy'n'paste'n'run it.

package com.stackoverflow;

import java.lang.reflect.Method;
import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;

public class Test {

    @Deprecated
    public static void main(String[] args) {
        Reflections reflections = new Reflections(new ConfigurationBuilder()
            .setUrls(ClasspathHelper.forPackage("com.stackoverflow"))
            .setScanners(new MethodAnnotationsScanner()));
        Set<Method> methods = reflections.getMethodsAnnotatedWith(Deprecated.class);
        System.out.println(methods);
    }

}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
1

No. But this is not inefficient at all.

For example spring is using the following code:

public static <A extends Annotation> A getAnnotation(
        Method method, Class<A> annotationType) {

    return BridgeMethodResolver.
       findBridgedMethod(method).getAnnotation(annotationType);
}

(where the BridgedMethodResolver is another topic, but it just returns a Method object)

Also, instead of comparing to null, you can check whether an annotation is present with isAnnotationPresent(YourAnnotation.class) (as suggested in the comments below the question)

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • Well it is something like O(m* (1 + a)) where m = number of methods and a = average number of annotations per method. a is often close to 0 so it's actually O(m). Something like O(log(m)) would be better if this code will be often invoked. – Łukasz Bownik Feb 10 '10 at 14:14
  • and `m` is rarely more than 10 ;) – Bozho Feb 10 '10 at 14:21
  • I wouldn't point to Spring as an example of efficiency--ever look at the stack traces generated when an exception is thrown within a method called by spring? It must drop through half a dozen levels of spring methods for each "real" method call. Luckily java is pretty fast overall and it doesn't seemm to cause a problem, but I think twice before calling a method on an object instantiated by spring in a tight loop.... – Bill K Aug 27 '12 at 21:02
1

If you're going to make several calls to this for every class you can create a descriptor like class which does nothing more than cache this type of information. Then when you want to retrieve the information you just look at it's descriptor.

To answer your question:

Class<?> _class = Whatever.class;
Annotation[] annos = _class.getAnnotations();

will return all annotations of a class. What you've done will only return the very first annotation of a method. Like wise:

Annotion[] annos = myMethod.getAnnotations();

returns all the annotations of a given method.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • won't this return only class-level annotarions? the method ones won't be included, and he's interested in them – Bozho Feb 10 '10 at 14:22
  • they are already cached in the `Method` object - it's using a Map – Bozho Feb 10 '10 at 14:33
  • Yes but you have to use reflection every time you'd want them. What I'm saying is get to that Map once and never go through reflection again. – wheaties Feb 10 '10 at 14:50