📄 methodmap.java
字号:
/*
* Copyright (c) 2003 The Visigoth Software Society. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Visigoth Software Society (http://www.visigoths.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
* project contributors may be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact visigoths@visigoths.org.
*
* 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
* nor may "FreeMarker" or "Visigoth" appear in their names
* without prior written permission of the Visigoth Software Society.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Visigoth Software Society. For more
* information on the Visigoth Software Society, please see
* http://www.visigoths.org/
*/
package freemarker.ext.beans;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import freemarker.template.TemplateModelException;
class MethodMap
{
private static final Class BIGDECIMAL_CLASS = java.math.BigDecimal.class;
private static final Class NUMBER_CLASS = java.lang.Number.class;
private static final Object[] EMPTY_ARGS = new Object[0];
private static final Class NULL_CLASS = java.lang.Object.class;
private static final ClassString EMPTY_STRING = new ClassString(EMPTY_ARGS);
private static final Object NO_SUCH_METHOD = new Object();
private static final Object AMBIGUOUS_METHOD = new Object();
private final String name;
// Cache of Class[] --> AccessibleObject. Maps the actual types involved in
// a method/constructor call to the most specific method/constructor for
// those types
private final Map selectorCache = new HashMap();
private Class[][] unwrapTypes;
private final List methods = new LinkedList();
MethodMap(String name)
{
this.name = name;
}
void addMethod(Method method)
{
methods.add(method);
updateUnwrapTypes(method.getParameterTypes());
}
void addConstructor(Constructor constructor)
{
methods.add(constructor);
updateUnwrapTypes(constructor.getParameterTypes());
}
private void updateUnwrapTypes(Class[] argTypes)
{
int l = argTypes.length - 1;
if(l == -1)
{
return;
}
if(unwrapTypes == null)
{
unwrapTypes = new Class[l + 1][];
unwrapTypes[l] = argTypes;
}
else if(unwrapTypes.length <= l)
{
Class[][] newUnwrapTypes = new Class[l + 1][];
System.arraycopy(unwrapTypes, 0, newUnwrapTypes, 0, unwrapTypes.length);
unwrapTypes = newUnwrapTypes;
unwrapTypes[l] = argTypes;
}
else
{
Class[] oldTypes = unwrapTypes[l];
if(oldTypes == null)
{
unwrapTypes[l] = argTypes;
}
else
{
for(int i = 0; i < oldTypes.length; ++i)
{
oldTypes[i] = getMostSpecificCommonType(oldTypes[i], argTypes[i]);
}
}
}
}
String getName()
{
return name;
}
Class[] getUnwrapTypes(List args) throws TemplateModelException
{
int l = args.size() - 1;
if(l == -1) {
return EMPTY_STRING.getClasses();
}
if(l < unwrapTypes.length) {
Class[] retval = unwrapTypes[l];
if(retval != null) {
return retval;
}
}
throw new TemplateModelException("No signature of method " +
name + " accepts " + (l + 1) + " arguments");
}
AccessibleObject getMostSpecific(Object[] args)
throws TemplateModelException
{
ClassString cs = null;
if(args == null)
{
args = EMPTY_ARGS;
cs = EMPTY_STRING;
}
else
{
cs = new ClassString(args);
}
synchronized(selectorCache)
{
Object obj = selectorCache.get(cs);
if(obj == null)
{
selectorCache.put(cs, obj = cs.getMostSpecific(methods));
}
if(obj instanceof AccessibleObject)
{
return (AccessibleObject)obj;
}
if(obj == NO_SUCH_METHOD)
{
throw new TemplateModelException("No signature of method " +
name + " matches " + cs.listArgumentTypes());
}
else
{
// Can be only AMBIGUOUS_METHOD
throw new TemplateModelException(
"Multiple signatures of method " + name + " match " +
cs.listArgumentTypes());
}
}
}
private static final class ClassString
{
private final Class[] classes;
ClassString(Object[] objects)
{
int l = objects.length;
classes = new Class[l];
for(int i = 0; i < l; ++i)
{
Object obj = objects[i];
classes[i] = obj == null ? NULL_CLASS : obj.getClass();
}
}
Class[] getClasses()
{
return classes;
}
public int hashCode()
{
int hash = 0;
for(int i = 0; i < classes.length; ++i)
{
hash ^= classes[i].hashCode();
}
return hash;
}
public boolean equals(Object o)
{
if(o instanceof ClassString)
{
ClassString cs = (ClassString)o;
if(cs.classes.length != classes.length)
{
return false;
}
for(int i = 0; i < classes.length; ++i)
{
if(cs.classes[i] != classes[i])
{
return false;
}
}
return true;
}
return false;
}
private static final int MORE_SPECIFIC = 0;
private static final int LESS_SPECIFIC = 1;
private static final int INDETERMINATE = 2;
Object getMostSpecific(List methods)
{
LinkedList applicables = getApplicables(methods);
if(applicables.isEmpty())
{
return NO_SUCH_METHOD;
}
if(applicables.size() == 1)
{
return applicables.getFirst();
}
LinkedList maximals = new LinkedList();
for (Iterator applicable = applicables.iterator();
applicable.hasNext();)
{
Object objapp = applicable.next();
Class[] appArgs = getParameterTypes(objapp);
boolean lessSpecific = false;
for (Iterator maximal = maximals.iterator();
!lessSpecific && maximal.hasNext();)
{
Object max = maximal.next();
switch(moreSpecific(appArgs, getParameterTypes(max)))
{
case MORE_SPECIFIC:
{
maximal.remove();
break;
}
case LESS_SPECIFIC:
{
lessSpecific = true;
break;
}
}
}
if(!lessSpecific)
{
maximals.addLast(objapp);
}
}
if(maximals.size() > 1)
{
return AMBIGUOUS_METHOD;
}
return maximals.getFirst();
}
private static Class[] getParameterTypes(Object obj)
{
if(obj instanceof Method)
{
return ((Method)obj).getParameterTypes();
}
if(obj instanceof Constructor)
{
return ((Constructor)obj).getParameterTypes();
}
// Cannot happen
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -