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.tools.reflect;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Arrays;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.Serializable;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.IOException;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.ObjectInputStream;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.ObjectOutputStream;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A runtime class metaobject.
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>A <code>ClassMetaobject</code> is created for every
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class of reflective objects.  It can be used to hold values
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * shared among the reflective objects of the same class.
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To obtain a class metaobject, calls <code>_getClass()</code>
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * on a reflective object.  For example,
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Metaobject
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Metalevel
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class ClassMetaobject implements Serializable {
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The base-level methods controlled by a metaobject
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * are renamed so that they begin with
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>methodPrefix "_m_"</code>.
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String methodPrefix = "_m_";
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final int methodPrefixLen = 3;
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class javaClass;
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Constructor[] constructors;
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Method[] methods;
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Specifies how a <code>java.lang.Class</code> object is loaded.
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If true, it is loaded by:
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If false, it is loaded by <code>Class.forName()</code>.
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The default value is false.
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static boolean useContextClassLoader = false;
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a <code>ClassMetaobject</code>.
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param params    <code>params[0]</code> is the name of the class
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  of the reflective objects.
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ClassMetaobject(String[] params)
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            javaClass = getClassObject(params[0]);
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (ClassNotFoundException e) {
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("not found: " + params[0]
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                       + ", useContextClassLoader: "
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                       + Boolean.toString(useContextClassLoader), e);
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        constructors = javaClass.getConstructors();
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methods = null;
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void writeObject(ObjectOutputStream out) throws IOException {
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.writeUTF(javaClass.getName());
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void readObject(ObjectInputStream in)
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, ClassNotFoundException
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        javaClass = getClassObject(in.readUTF());
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        constructors = javaClass.getConstructors();
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methods = null;
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class getClassObject(String name) throws ClassNotFoundException {
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (useContextClassLoader)
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return Thread.currentThread().getContextClassLoader()
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                   .loadClass(name);
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return Class.forName(name);
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the <code>java.lang.Class</code> representing this class.
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Class getJavaClass() {
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return javaClass;
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the name of this class.
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final String getName() {
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return javaClass.getName();
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if <code>obj</code> is an instance of this class.
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final boolean isInstance(Object obj) {
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return javaClass.isInstance(obj);
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Creates a new instance of the class.
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param args              the arguments passed to the constructor.
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Object newInstance(Object[] args)
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCreateException
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = constructors.length;
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i) {
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return constructors[i].newInstance(args);
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (IllegalArgumentException e) {
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // try again
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (InstantiationException e) {
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new CannotCreateException(e);
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (IllegalAccessException e) {
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new CannotCreateException(e);
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (InvocationTargetException e) {
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new CannotCreateException(e);
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new CannotCreateException("no constructor matches");
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Is invoked when <code>static</code> fields of the base-level
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * class are read and the runtime system intercepts it.
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This method simply returns the value of the field.
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Every subclass of this class should redefine this method.
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object trapFieldRead(String name) {
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class jc = getJavaClass();
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return jc.getField(name).get(null);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NoSuchFieldException e) {
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.toString());
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (IllegalAccessException e) {
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.toString());
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Is invoked when <code>static</code> fields of the base-level
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * class are modified and the runtime system intercepts it.
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This method simply sets the field to the given value.
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Every subclass of this class should redefine this method.
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void trapFieldWrite(String name, Object value) {
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class jc = getJavaClass();
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jc.getField(name).set(null, value);
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NoSuchFieldException e) {
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.toString());
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (IllegalAccessException e) {
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.toString());
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Invokes a method whose name begins with
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>methodPrefix "_m_"</code> and the identifier.
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @exception CannotInvokeException         if the invocation fails.
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static public Object invoke(Object target, int identifier, Object[] args)
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws Throwable
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Method[] allmethods = target.getClass().getMethods();
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = allmethods.length;
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String head = methodPrefix + identifier;
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i)
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (allmethods[i].getName().startsWith(head)) {
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                try {
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    return allmethods[i].invoke(target, args);
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                } catch (java.lang.reflect.InvocationTargetException e) {
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw e.getTargetException();
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                } catch (java.lang.IllegalAccessException e) {
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw new CannotInvokeException(e);
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new CannotInvokeException("cannot find a method");
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Is invoked when <code>static</code> methods of the base-level
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * class are called and the runtime system intercepts it.
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This method simply executes the intercepted method invocation
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * with the original parameters and returns the resulting value.
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Every subclass of this class should redefine this method.
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object trapMethodcall(int identifier, Object[] args)
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws Throwable
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Method[] m = getReflectiveMethods();
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return m[identifier].invoke(null, args);
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (java.lang.reflect.InvocationTargetException e) {
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw e.getTargetException();
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (java.lang.IllegalAccessException e) {
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotInvokeException(e);
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns an array of the methods defined on the given reflective
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * object.  This method is for the internal use only.
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Method[] getReflectiveMethods() {
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (methods != null)
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return methods;
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class baseclass = getJavaClass();
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Method[] allmethods = baseclass.getDeclaredMethods();
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = allmethods.length;
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int[] index = new int[n];
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int max = 0;
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i) {
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Method m = allmethods[i];
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String mname = m.getName();
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (mname.startsWith(methodPrefix)) {
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int k = 0;
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                for (int j = methodPrefixLen;; ++j) {
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    char c = mname.charAt(j);
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if ('0' <= c && c <= '9')
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        k = k * 10 + c - '0';
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    else
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        break;
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                index[i] = ++k;
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (k > max)
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    max = k;
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methods = new Method[max];
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i)
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (index[i] > 0)
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                methods[index[i] - 1] = allmethods[i];
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return methods;
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the <code>java.lang.reflect.Method</code> object representing
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the method specified by <code>identifier</code>.
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Note that the actual method returned will be have an altered,
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * reflective name i.e. <code>_m_2_..</code>.
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param identifier        the identifier index
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          given to <code>trapMethodcall()</code> etc.
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see Metaobject#trapMethodcall(int,Object[])
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see #trapMethodcall(int,Object[])
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Method getMethod(int identifier) {
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return getReflectiveMethods()[identifier];
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the name of the method specified
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * by <code>identifier</code>.
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final String getMethodName(int identifier) {
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String mname = getReflectiveMethods()[identifier].getName();
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int j = ClassMetaobject.methodPrefixLen;
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (;;) {
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            char c = mname.charAt(j++);
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (c < '0' || '9' < c)
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                break;
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return mname.substring(j);
31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns an array of <code>Class</code> objects representing the
31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * formal parameter types of the method specified
32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * by <code>identifier</code>.
32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Class[] getParameterTypes(int identifier) {
32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return getReflectiveMethods()[identifier].getParameterTypes();
32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns a <code>Class</code> objects representing the
32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * return type of the method specified by <code>identifier</code>.
32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final Class getReturnType(int identifier) {
33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return getReflectiveMethods()[identifier].getReturnType();
33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the identifier index of the method, as identified by its
33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * original name.
33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>This method is useful, in conjuction with
33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * to the original method in the reflected class (i.e. not the proxy
34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * method), using the original name of the method.
34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Written by Brett Randall and Shigeru Chiba.
34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param originalName      The original name of the reflected method
34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param argTypes          array of Class specifying the method signature
34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return      the identifier index of the original method
34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws NoSuchMethodException    if the method does not exist
34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see ClassMetaobject#getMethod(int)
35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public final int getMethodIndex(String originalName, Class[] argTypes)
35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws NoSuchMethodException
35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Method[] mthds = getReflectiveMethods();
35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < mthds.length; i++) {
35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (mthds[i] == null)
35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                continue;
35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // check name and parameter types match
36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (getMethodName(i).equals(originalName)
36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return i;
36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new NoSuchMethodException("Method " + originalName
36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                        + " not found");
36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
370