views:

92

answers:

3

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;
          }
        }
+1  A: 

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
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.
lbownik
and `m` is rarely more than 10 ;)
Bozho
hmm - good point :)
lbownik
+1  A: 

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
won't this return only class-level annotarions? the method ones won't be included, and he's interested in them
Bozho
they are already cached in the `Method` object - it's using a Map
Bozho
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
A: 

Take a look for Google Reflections. It's a library which has already optimized the most of it all. There's also a Reflections#getMethodsAnnotatedWith() which perfectly 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.getUrlsForPackagePrefix("com.stackoverflow"))
            .setScanners(new MethodAnnotationsScanner()));
        Set<Method> methods = reflections.getMethodsAnnotatedWith(Deprecated.class);
        System.out.println(methods);
    }

}
BalusC