⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 methodmap.java

📁 freemaker安装软件
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -