package com.maxifier.guice.lifecycle; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * Cache for saving method-annotation association * * Project: X-Guice * Date: 10.09.2009 * Time: 17:19:42 * <p/> * Copyright (c) 1999-2009 Magenta Corporation Ltd. All Rights Reserved. * Magenta Technology proprietary and confidential. * Use is subject to license terms. * * @author Aleksey Didik */ class AnnotatedMethodCache { private final Class<? extends Annotation>[] annotation; private static final int INITIAL_CAPACITY = 50; private final Map<Class<?>, Method[]> cache = new HashMap<Class<?>, Method[]>(INITIAL_CAPACITY); public AnnotatedMethodCache(Class<? extends Annotation>... annotation) { this.annotation = annotation; } public Method[] get(Class<?> key) { Method[] result = cache.get(key); if (result == null) { MethodArray methodArray = new MethodArray(); //add all from super class get0(key, methodArray); result = methodArray.getArray(); cache.put(key, result); } return result; } private void get0(Class<?> key, MethodArray methods) { if (key.equals(Object.class)) { return; } //from get0(key.getSuperclass(), methods); for (Method method : key.getDeclaredMethods()) { for (Class<? extends Annotation> aClass : annotation) { if (method.isAnnotationPresent(aClass)) { if (!method.isAccessible()) { method.setAccessible(true); } methods.addIfNotPresent(method); } } } } //brief copy from Class.class private static class MethodArray { private Method[] methods; private int length; MethodArray() { methods = new Method[5]; length = 0; } void add(Method method) { if (length == methods.length) { methods = Arrays.copyOf(methods, methods.length + 2); } methods[length++] = method; } void addIfNotPresent(Method newMethod) { for (int i = 0; i < length; i++) { Method method = methods[i]; if (isEqualByNameAndSignature(method, newMethod)) { return; } } add(newMethod); } boolean isEqualByNameAndSignature(Method m1, Method m2) { return m1.getReturnType() == m2.getReturnType() && m1.getName().equals(m2.getName()) && isArrayContentsEq(m1.getParameterTypes(), m2.getParameterTypes()); } @SuppressWarnings({"ReturnOfCollectionOrArrayField"}) //class used only from owner Method[] getArray() { compactAndTrim(); return methods; } void compactAndTrim() { int newPos = 0; // Get rid of null slots for (int pos = 0; pos < length; pos++) { Method method = methods[pos]; if (method != null) { if (pos != newPos) { methods[newPos] = method; } newPos++; } } if (newPos != methods.length) { methods = Arrays.copyOf(methods, newPos); } } boolean isArrayContentsEq(Object[] a1, Object[] a2) { if (a1 == null) { return a2 == null || a2.length == 0; } if (a2 == null) { return a1.length == 0; } if (a1.length != a2.length) { return false; } for (int i = 0; i < a1.length; i++) { if (!a1[i].equals(a2[i])) { return false; } } return true; } } @Override public String toString() { return "AnnotatedMethodCache{" + "annotation=" + (annotation == null ? null : Arrays.asList(annotation)) + '}'; } }