package org.myrobotlab.codec;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.TreeMap;
public class MethodCache {
static final private HashMap<String, Method> cache = new HashMap<String, Method>();
static final public String getSignature(Class<?> clazz, String methodName, int ordinal) {
return String.format("%s/%s-%d", clazz.getSimpleName(), methodName, ordinal);
}
static final public Class<?>[] getCandidateOnOrdinalSignature(Class<?> clazz, String methodName, int ordinal) throws NoSuchMethodException {
String signature = getSignature(clazz, methodName, ordinal);
if (cache.containsKey(signature)) {
Method m = cache.get(signature);
return m.getParameterTypes();
} else {
TreeMap<Integer, Method> methodScore = new TreeMap<Integer, Method>();
// changed to getMethods to support inheritance
// if failure - overloading funny re-implementing a vTable in c++
// Method[] methods = clazz.getDeclaredMethods();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// FIXME - future Many to one Map - if incoming data can "hint" would be
// an optimization
if (methodName.equals(method.getName())) {
// name matches - lets do more checking
Class<?>[] pTypes = method.getParameterTypes();
int score = 0;
if (ordinal == pTypes.length) {
// param length matches
boolean interfaceInParamList = false;
for (int i = 0; i < pTypes.length; ++i) {
// we don't support interfaces
// because what will we decode too ?
// we just can't ! :)
Class<?> type = pTypes[i];
/*
* BAD ASSUMPTION - SOME CODECs have a default class they
* serialize from for List Map HashSet etc..
*/
/*
* if (type.isInterface()) { interfaceInParamList = true; break; }
*/
if (type.isPrimitive() || type.equals(String.class)) {
++score;
}
}
if (!interfaceInParamList) {
// rank / score method
methodScore.put(score, method);
}
}
}
} // we checked all methods
if (methodScore.size() > 0) {
return methodScore.get(methodScore.lastKey()).getParameterTypes();
} else {
throw new NoSuchMethodException(String.format("could not find %s.%s(ordinal %d) in declared methods", clazz.getSimpleName(), methodName, ordinal));
}
}
}
final public static void cache(Class<?> clazz, Method method) {
cache.put(getSignature(clazz, method.getName(), method.getParameterTypes().length), method);
}
}