169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.runtime;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A support class for implementing <code>$sig</code> and
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>$type</code>.
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This support class is required at runtime
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * only if <code>$sig</code> or <code>$type</code> is used.
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Desc {
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Specifies how a <code>java.lang.Class</code> object is loaded.
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If true, it is loaded by:
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If false, it is loaded by <code>Class.forName()</code>.
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The default value is false.
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static boolean useContextClassLoader = false;
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Class getClassObject(String name)
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws ClassNotFoundException
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (useContextClassLoader)
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return Thread.currentThread().getContextClassLoader()
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   .loadClass(name);
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return Class.forName(name);
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Interprets the given class name.
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It is used for implementing <code>$class</code>.
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static Class getClazz(String name) {
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return getClassObject(name);
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (ClassNotFoundException e) {
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    "$class: internal error, could not find class '" + name
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    + "' (Desc.useContextClassLoader: "
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    + Boolean.toString(useContextClassLoader) + ")", e);
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Interprets the given type descriptor representing a method
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * signature.  It is used for implementing <code>$sig</code>.
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static Class[] getParams(String desc) {
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (desc.charAt(0) != '(')
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("$sig: internal error");
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return getType(desc, desc.length(), 1, 0);
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Interprets the given type descriptor.
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It is used for implementing <code>$type</code>.
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static Class getType(String desc) {
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class[] result = getType(desc, desc.length(), 0, 0);
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (result == null || result.length != 1)
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("$type: internal error");
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return result[0];
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Class[] getType(String desc, int descLen,
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                   int start, int num) {
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class clazz;
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (start >= descLen)
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return new Class[num];
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        char c = desc.charAt(start);
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        switch (c) {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'Z' :
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Boolean.TYPE;
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'C' :
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Character.TYPE;
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'B' :
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Byte.TYPE;
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'S' :
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Short.TYPE;
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'I' :
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Integer.TYPE;
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'J' :
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Long.TYPE;
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'F' :
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Float.TYPE;
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'D' :
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Double.TYPE;
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'V' :
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = Void.TYPE;
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            break;
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case 'L' :
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        case '[' :
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return getClassType(desc, descLen, start, num);
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        default :
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return new Class[num];
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class[] result = getType(desc, descLen, start + 1, num + 1);
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        result[num] = clazz;
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return result;
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Class[] getClassType(String desc, int descLen,
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                        int start, int num) {
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int end = start;
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (desc.charAt(end) == '[')
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ++end;
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (desc.charAt(end) == 'L') {
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            end = desc.indexOf(';', end);
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (end < 0)
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new IndexOutOfBoundsException("bad descriptor");
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String cname;
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (desc.charAt(start) == 'L')
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cname = desc.substring(start + 1, end);
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cname = desc.substring(start, end + 1);
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class[] result = getType(desc, descLen, end + 1, num + 1);
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            result[num] = getClassObject(cname.replace('/', '.'));
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (ClassNotFoundException e) {
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // "new RuntimeException(e)" is not available in JDK 1.3.
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.getMessage());
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return result;
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
162