/*
* Copyright 2016 Nabarun Mondal
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.noga.njexl.lang.internal.introspection;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A map of method names to methods.
* @since 1.0
*/
final class MethodMap {
/**
* Keep track of all methods with the same name.
*/
private final Map<String, List<Method>> methodByNameMap = new HashMap<String, List<Method>>();
/**
* Add a method to a list of methods by name. For a particular class we are
* keeping track of all the methods with the same name.
*
* @param method the method.
*/
public synchronized void add(Method method) {
String methodName = method.getName();
List<Method> l = methodByNameMap.get(methodName);
if (l == null) {
l = new ArrayList<Method>();
methodByNameMap.put(methodName, l);
}
l.add(method);
}
/**
* Return a list of methods with the same name.
*
* @param key the name.
* @return List list of methods.
*/
public synchronized List<Method> get(String key) {
return methodByNameMap.get(key);
}
/**
* Returns the array of method names accessible in this class.
* @return the array of names
*/
public synchronized String[] names() {
java.util.Set<String> set = methodByNameMap.keySet();
return set.toArray(new String[set.size()]);
}
/**
* <p>
* Find a method. Attempts to find the
* most specific applicable method using the
* algorithm described in the JLS section
* 15.12.2 (with the exception that it can't
* distinguish a primitive type argument from
* an object type argument, since in reflection
* primitive type arguments are represented by
* their object counterparts, so for an argument of
* type (say) java.lang.Integer, it will not be able
* to decide between a method that takes int and a
* method that takes java.lang.Integer as a parameter.
* </p>
*
* <p>
* This turns out to be a relatively rare case
* where this is needed - however, functionality
* like this is needed.
* </p>
*
* @param methodName name of method
* @param args the actual arguments with which the method is called
* @return the most specific applicable method, or null if no
* method is applicable.
* @throws MethodKey.AmbiguousException if there is more than one maximally
* specific applicable method
*/
// CSOFF: RedundantThrows
public Method find(String methodName, Object[] args) throws MethodKey.AmbiguousException {
return find(new MethodKey(methodName, args));
}
/**
* Finds a method by key.
* @param methodKey the key
* @return the method
* @throws MethodKey.AmbiguousException if find is ambiguous
*/
Method find(MethodKey methodKey) throws MethodKey.AmbiguousException {
List<Method> methodList = get(methodKey.getMethod());
if (methodList == null) {
return null;
}
return methodKey.getMostSpecificMethod(methodList);
} // CSON: RedundantThrows
}