123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.tools.reflect;
-
- import java.lang.reflect.*;
- import java.util.Arrays;
- import java.io.Serializable;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
-
- /**
- * A runtime class metaobject.
- *
- * <p>A <code>ClassMetaobject</code> is created for every
- * class of reflective objects. It can be used to hold values
- * shared among the reflective objects of the same class.
- *
- * <p>To obtain a class metaobject, calls <code>_getClass()</code>
- * on a reflective object. For example,
- *
- * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
- * </pre></ul>
- *
- * @see javassist.tools.reflect.Metaobject
- * @see javassist.tools.reflect.Metalevel
- */
- public class ClassMetaobject implements Serializable {
- /**
- * The base-level methods controlled by a metaobject
- * are renamed so that they begin with
- * <code>methodPrefix "_m_"</code>.
- */
- static final String methodPrefix = "_m_";
- static final int methodPrefixLen = 3;
-
- private Class javaClass;
- private Constructor[] constructors;
- private Method[] methods;
-
- /**
- * Specifies how a <code>java.lang.Class</code> object is loaded.
- *
- * <p>If true, it is loaded by:
- * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
- * <p>If false, it is loaded by <code>Class.forName()</code>.
- * The default value is false.
- */
- public static boolean useContextClassLoader = false;
-
- /**
- * Constructs a <code>ClassMetaobject</code>.
- *
- * @param params <code>params[0]</code> is the name of the class
- * of the reflective objects.
- */
- public ClassMetaobject(String[] params)
- {
- try {
- javaClass = getClassObject(params[0]);
- }
- catch (ClassNotFoundException e) {
- javaClass = null;
- }
-
- constructors = javaClass.getConstructors();
- methods = null;
- }
-
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.writeUTF(javaClass.getName());
- }
-
- private void readObject(ObjectInputStream in)
- throws IOException, ClassNotFoundException
- {
- javaClass = getClassObject(in.readUTF());
- constructors = javaClass.getConstructors();
- methods = null;
- }
-
- private Class getClassObject(String name) throws ClassNotFoundException {
- if (useContextClassLoader)
- return Thread.currentThread().getContextClassLoader()
- .loadClass(name);
- else
- return Class.forName(name);
- }
-
- /**
- * Obtains the <code>java.lang.Class</code> representing this class.
- */
- public final Class getJavaClass() {
- return javaClass;
- }
-
- /**
- * Obtains the name of this class.
- */
- public final String getName() {
- return javaClass.getName();
- }
-
- /**
- * Returns true if <code>obj</code> is an instance of this class.
- */
- public final boolean isInstance(Object obj) {
- return javaClass.isInstance(obj);
- }
-
- /**
- * Creates a new instance of the class.
- *
- * @param args the arguments passed to the constructor.
- */
- public final Object newInstance(Object[] args)
- throws CannotCreateException
- {
- int n = constructors.length;
- for (int i = 0; i < n; ++i) {
- try {
- return constructors[i].newInstance(args);
- }
- catch (IllegalArgumentException e) {
- // try again
- }
- catch (InstantiationException e) {
- throw new CannotCreateException(e);
- }
- catch (IllegalAccessException e) {
- throw new CannotCreateException(e);
- }
- catch (InvocationTargetException e) {
- throw new CannotCreateException(e);
- }
- }
-
- throw new CannotCreateException("no constructor matches");
- }
-
- /**
- * Is invoked when <code>static</code> fields of the base-level
- * class are read and the runtime system intercepts it.
- * This method simply returns the value of the field.
- *
- * <p>Every subclass of this class should redefine this method.
- */
- public Object trapFieldRead(String name) {
- Class jc = getJavaClass();
- try {
- return jc.getField(name).get(null);
- }
- catch (NoSuchFieldException e) {
- throw new RuntimeException(e.toString());
- }
- catch (IllegalAccessException e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- /**
- * Is invoked when <code>static</code> fields of the base-level
- * class are modified and the runtime system intercepts it.
- * This method simply sets the field to the given value.
- *
- * <p>Every subclass of this class should redefine this method.
- */
- public void trapFieldWrite(String name, Object value) {
- Class jc = getJavaClass();
- try {
- jc.getField(name).set(null, value);
- }
- catch (NoSuchFieldException e) {
- throw new RuntimeException(e.toString());
- }
- catch (IllegalAccessException e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- /**
- * Invokes a method whose name begins with
- * <code>methodPrefix "_m_"</code> and the identifier.
- *
- * @exception CannotInvokeException if the invocation fails.
- */
- static public Object invoke(Object target, int identifier, Object[] args)
- throws Throwable
- {
- Method[] allmethods = target.getClass().getMethods();
- int n = allmethods.length;
- String head = methodPrefix + identifier;
- for (int i = 0; i < n; ++i)
- if (allmethods[i].getName().startsWith(head)) {
- try {
- return allmethods[i].invoke(target, args);
- } catch (java.lang.reflect.InvocationTargetException e) {
- throw e.getTargetException();
- } catch (java.lang.IllegalAccessException e) {
- throw new CannotInvokeException(e);
- }
- }
-
- throw new CannotInvokeException("cannot find a method");
- }
-
- /**
- * Is invoked when <code>static</code> methods of the base-level
- * class are called and the runtime system intercepts it.
- * This method simply executes the intercepted method invocation
- * with the original parameters and returns the resulting value.
- *
- * <p>Every subclass of this class should redefine this method.
- */
- public Object trapMethodcall(int identifier, Object[] args)
- throws Throwable
- {
- try {
- Method[] m = getReflectiveMethods();
- return m[identifier].invoke(null, args);
- }
- catch (java.lang.reflect.InvocationTargetException e) {
- throw e.getTargetException();
- }
- catch (java.lang.IllegalAccessException e) {
- throw new CannotInvokeException(e);
- }
- }
-
- /**
- * Returns an array of the methods defined on the given reflective
- * object. This method is for the internal use only.
- */
- public final Method[] getReflectiveMethods() {
- if (methods != null)
- return methods;
-
- Class baseclass = getJavaClass();
- Method[] allmethods = baseclass.getDeclaredMethods();
- int n = allmethods.length;
- int[] index = new int[n];
- int max = 0;
- for (int i = 0; i < n; ++i) {
- Method m = allmethods[i];
- String mname = m.getName();
- if (mname.startsWith(methodPrefix)) {
- int k = 0;
- for (int j = methodPrefixLen;; ++j) {
- char c = mname.charAt(j);
- if ('0' <= c && c <= '9')
- k = k * 10 + c - '0';
- else
- break;
- }
-
- index[i] = ++k;
- if (k > max)
- max = k;
- }
- }
-
- methods = new Method[max];
- for (int i = 0; i < n; ++i)
- if (index[i] > 0)
- methods[index[i] - 1] = allmethods[i];
-
- return methods;
- }
-
- /**
- * Returns the <code>java.lang.reflect.Method</code> object representing
- * the method specified by <code>identifier</code>.
- *
- * <p>Note that the actual method returned will be have an altered,
- * reflective name i.e. <code>_m_2_..</code>.
- *
- * @param identifier the identifier index
- * given to <code>trapMethodcall()</code> etc.
- * @see Metaobject#trapMethodcall(int,Object[])
- * @see #trapMethodcall(int,Object[])
- */
- public final Method getMethod(int identifier) {
- return getReflectiveMethods()[identifier];
- }
-
- /**
- * Returns the name of the method specified
- * by <code>identifier</code>.
- */
- public final String getMethodName(int identifier) {
- String mname = getReflectiveMethods()[identifier].getName();
- int j = ClassMetaobject.methodPrefixLen;
- for (;;) {
- char c = mname.charAt(j++);
- if (c < '0' || '9' < c)
- break;
- }
-
- return mname.substring(j);
- }
-
- /**
- * Returns an array of <code>Class</code> objects representing the
- * formal parameter types of the method specified
- * by <code>identifier</code>.
- */
- public final Class[] getParameterTypes(int identifier) {
- return getReflectiveMethods()[identifier].getParameterTypes();
- }
-
- /**
- * Returns a <code>Class</code> objects representing the
- * return type of the method specified by <code>identifier</code>.
- */
- public final Class getReturnType(int identifier) {
- return getReflectiveMethods()[identifier].getReturnType();
- }
-
- /**
- * Returns the identifier index of the method, as identified by its
- * original name.
- *
- * <p>This method is useful, in conjuction with
- * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
- * to the original method in the reflected class (i.e. not the proxy
- * method), using the original name of the method.
- *
- * <p>Written by Brett Randall and Shigeru Chiba.
- *
- * @param originalName The original name of the reflected method
- * @param argTypes array of Class specifying the method signature
- * @return the identifier index of the original method
- * @throws NoSuchMethodException if the method does not exist
- *
- * @see ClassMetaobject#getMethod(int)
- */
- public final int getMethodIndex(String originalName, Class[] argTypes)
- throws NoSuchMethodException
- {
- Method[] mthds = getReflectiveMethods();
- for (int i = 0; i < mthds.length; i++) {
- if (mthds[i] == null)
- continue;
-
- // check name and parameter types match
- if (getMethodName(i).equals(originalName)
- && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
- return i;
- }
-
- throw new NoSuchMethodException("Method " + originalName
- + " not found");
- }
- }
|