Reputation: 21134
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 Servlet
s.
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
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