All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.jpattern.org.cojen.classfile.MethodDesc Maven / Gradle / Ivy

Go to download

This is a copy of the good Cojen project from http://cojen.sourceforge.net/ with package name changed

The newest version!
/*
 *  Copyright 2004-2010 Brian S O'Neill
 *
 *  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.googlecode.jpattern.org.cojen.classfile;

import java.io.Serializable;
import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.ArrayList;

import com.googlecode.jpattern.org.cojen.util.WeakCanonicalSet;

/**
 * This class is used to build method descriptor strings as 
 * defined in The Java Virtual Machine Specification, section 4.3.3.
 * MethodDesc instances are canonicalized and therefore "==" comparable.
 *
 * @author Brian S O'Neill
 */
public class MethodDesc extends Descriptor implements Serializable {
    private static final TypeDesc[] EMPTY_PARAMS = new TypeDesc[0];

    // MethodDesc and TypeDesc can share the same instance cache.
    private final static WeakCanonicalSet cInstances = TypeDesc.cInstances;

    static MethodDesc intern(MethodDesc desc) {
        return cInstances.put(desc);
    }

    /**
     * Acquire a MethodDesc from a set of arguments.
     * @param ret return type of method; null implies void
     * @param params parameters to method; null implies none
     */
    public static MethodDesc forArguments(TypeDesc ret, TypeDesc[] params) {
        if (ret == null) {
            ret = TypeDesc.VOID;
        }
        if (params == null || params.length == 0) {
            params = EMPTY_PARAMS;
        }
        return intern(new MethodDesc(ret, params));
    }

    /**
     * Acquire a MethodDesc from a type descriptor. This syntax is described in
     * section 4.3.3, Method Descriptors.
     */
    public static MethodDesc forDescriptor(String desc) 
        throws IllegalArgumentException
    {
        try {
            int cursor = 0;
            char c;

            if ((c = desc.charAt(cursor++)) != '(') {
                throw invalidDescriptor(desc);
            }

            StringBuffer buf = new StringBuffer();
            List list = new ArrayList();

            while ((c = desc.charAt(cursor++)) != ')') {
                switch (c) {
                case 'V':
                case 'I':
                case 'C':
                case 'Z':
                case 'D':
                case 'F':
                case 'J':
                case 'B':
                case 'S':
                    buf.append(c);
                    break;
                case '[':
                    buf.append(c);
                    continue;
                case 'L':
                    while (true) {
                        buf.append(c);
                        if (c == ';') {
                            break;
                        }
                        c = desc.charAt(cursor++);
                    }
                    break;
                default:
                    throw invalidDescriptor(desc);
                }

                list.add(TypeDesc.forDescriptor(buf.toString()));
                buf.setLength(0);
            }

            TypeDesc ret = TypeDesc.forDescriptor(desc.substring(cursor));

            TypeDesc[] tds = list.toArray(new TypeDesc[list.size()]);

            return intern(new MethodDesc(desc, ret, tds));
        } catch (NullPointerException e) {
            throw invalidDescriptor(desc);
        } catch (IndexOutOfBoundsException e) {
            throw invalidDescriptor(desc);
        }
    }

    public static MethodDesc forMethod(Method method) {
        Class[] paramClasses = method.getParameterTypes();
        TypeDesc[] paramTypes;
        if (paramClasses == null || paramClasses.length == 0) {
            paramTypes = EMPTY_PARAMS;
        } else {
            paramTypes = new TypeDesc[paramClasses.length];
            for (int i=paramClasses.length; --i>=0; ) {
                paramTypes[i] = TypeDesc.forClass(paramClasses[i]);
            }
        }
        return forArguments(TypeDesc.forClass(method.getReturnType()), paramTypes);
    }

    private static IllegalArgumentException invalidDescriptor(String desc) {
        return new IllegalArgumentException("Invalid descriptor: " + desc);
    }

    private transient final String mDescriptor;
    private transient final TypeDesc mRetType;
    private transient final TypeDesc[] mParams;
    
    private MethodDesc(TypeDesc ret, TypeDesc[] params) {
        mDescriptor = generateDescriptor(ret, params);
        mRetType = ret;
        mParams = params;
    }

    private MethodDesc(String desc, TypeDesc ret, TypeDesc[] params) {
        mDescriptor = desc;
        mRetType = ret;
        mParams = params;
    }

    /**
     * Returns a method descriptor string, excluding generics.
     */
    public String getDescriptor() {
        return mDescriptor;
    }

    /**
     * Returns a method descriptor string, including any generics.
     */
    //public abstract String getGenericDescriptor();

    /**
     * Returns the described return type, which is TypeDesc.VOID if void.
     */
    public TypeDesc getReturnType() {
        return mRetType;
    }

    public int getParameterCount() {
        return mParams.length;
    }

    public TypeDesc[] getParameterTypes() {
        TypeDesc[] params = mParams;
        return (params != EMPTY_PARAMS) ? (TypeDesc[])params.clone() : params;
    }

    /**
     * Returns this in Java method signature syntax.
     *
     * @param name method name
     */
    public String toMethodSignature(String name) {
        return toMethodSignature(name, false);
    }

    /**
     * Returns this in Java method signature syntax.
     *
     * @param name method name
     * @param varargs request that the last argument, if it is an array, to
     * be formatted in varargs syntax.
     */
    public String toMethodSignature(String name, boolean varargs) {
        StringBuffer buf = new StringBuffer();
        buf.append(mRetType.getFullName());
        buf.append(' ');
        buf.append(name);
        buf.append('(');

        TypeDesc[] params = mParams;
        for (int i=0; i 0) {
                buf.append(", ");
            }
            TypeDesc param = params[i];
            if (varargs && param.isArray() && i == (params.length - 1)) {
                buf.append(param.getComponentType().getFullName());
                buf.append("...");
            } else {
                buf.append(param.getFullName());
            }
        }

        return buf.append(')').toString();
    }

    public String toString() {
        // TODO: Return generic descriptor
        return mDescriptor;
    }

    public int hashCode() {
        return mDescriptor.hashCode();
    }

    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (other instanceof MethodDesc) {
            return ((MethodDesc)other).mDescriptor.equals(mDescriptor);
        }
        return false;
    }

    Object writeReplace() throws ObjectStreamException {
        return new External(mDescriptor);
    }

    private static String generateDescriptor(TypeDesc ret, TypeDesc[] params) {
        int length = ret.getDescriptor().length() + 2;
        int paramsLength = params.length;
        for (int i=paramsLength; --i >=0; ) {
            length += params[i].getDescriptor().length();
        }
        char[] buf = new char[length];
        buf[0] = '(';
        int index = 1;
        String paramDesc;
        for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy