LppEdd
LppEdd

Reputation: 21134

Reflection - Method caching for multiple subclasses

I've got one abstract class which is extended by multiple concrete classes. The abstract class initialization block fetch all the methods of the current class hierarchy searching for particular annotated methods.

ConcreteClass2 > ConcreteClass1 > AbstractClass
OtherConcrete1 > AbstractClass

{
   ...

   final List<Method> methods = new ArrayList<>(16);
   Clazz<?> clazz = getClass();

   while (clazz != Object.class) {
      for (final Method method : clazz.getDeclaredMethods()) {
         if (method.isAnnotationPresent(MyAnnotation.class)) {
            methods.add(method);
         }
      }

      clazz = clazz.getSuperclass();
   }

   METHODS.put(getClass(), methods);

   ...
}

These concrete classes are instantiated in a web/application server and are used inside Servlets.

As per se Reflection is not the fastest, and as I do not want to repeat the scan every time a concrete type is instantiated (new), what is the best strategy to cache the annotated Method's.

I'm actually using ConcurrentHashMap as <Class<? extends AbstractClass>, List<Method>>, and In the initialization block I check if the Map already contains an entry for the uppermost concrete type.

However I do not think this is the best way to handle it. And by the way, I cannot have external dependencies.

Upvotes: 1

Views: 474

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726599

If you are on Java 8, use computeIfAbsent to avoid recomputing the set of methods with annotations:

private static final ConcurrentMap<Class<?>,List<Method>> METHODS = new ConcurrentHashMap<>();
...
Clazz<?> clazz = getClass();
METHODS.computeIfAbsent(clazz, c -> findMethods(c));
...
private static List<Method> findMethods(Class<?> clazz) {
    final List<Method> methods = new ArrayList<>(16);
    while (clazz != Object.class) {
        for (final Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                methods.add(method);
            }
        }
        clazz = clazz.getSuperclass();
    }
    return methods;
}

This would cache methods per class, and avoid recomputing List<Method> for the same class.

Upvotes: 1

Related Questions