KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > reflect > ClassMetaobject


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.reflect;
17
18 import java.lang.reflect.*;
19 import java.util.Arrays JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.ObjectInputStream JavaDoc;
23 import java.io.ObjectOutputStream JavaDoc;
24
25 /**
26  * A runtime class metaobject.
27  *
28  * <p>A <code>ClassMetaobject</code> is created for every
29  * class of reflective objects. It can be used to hold values
30  * shared among the reflective objects of the same class.
31  *
32  * <p>To obtain a class metaobject, calls <code>_getClass()</code>
33  * on a reflective object. For example,
34  *
35  * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
36  * </pre></ul>
37  *
38  * @see javassist.reflect.Metaobject
39  * @see javassist.reflect.Metalevel
40  */

41 public class ClassMetaobject implements Serializable JavaDoc {
42     /**
43      * The base-level methods controlled by a metaobject
44      * are renamed so that they begin with
45      * <code>methodPrefix "_m_"</code>.
46      */

47     static final String JavaDoc methodPrefix = "_m_";
48     static final int methodPrefixLen = 3;
49
50     private Class JavaDoc javaClass;
51     private Constructor[] constructors;
52     private Method[] methods;
53
54     /**
55      * Specifies how a <code>java.lang.Class</code> object is loaded.
56      *
57      * <p>If true, it is loaded by:
58      * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
59      * <p>If false, it is loaded by <code>Class.forName()</code>.
60      * The default value is false.
61      */

62     public static boolean useContextClassLoader = false;
63
64     /**
65      * Constructs a <code>ClassMetaobject</code>.
66      *
67      * @param params <code>params[0]</code> is the name of the class
68      * of the reflective objects.
69      */

70     public ClassMetaobject(String JavaDoc[] params)
71     {
72         try {
73             javaClass = getClassObject(params[0]);
74         }
75         catch (ClassNotFoundException JavaDoc e) {
76             javaClass = null;
77         }
78
79         constructors = javaClass.getConstructors();
80         methods = null;
81     }
82
83     private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
84         out.writeUTF(javaClass.getName());
85     }
86
87     private void readObject(ObjectInputStream JavaDoc in)
88         throws IOException JavaDoc, ClassNotFoundException JavaDoc
89     {
90         javaClass = getClassObject(in.readUTF());
91         constructors = javaClass.getConstructors();
92         methods = null;
93     }
94
95     private Class JavaDoc getClassObject(String JavaDoc name) throws ClassNotFoundException JavaDoc {
96         if (useContextClassLoader)
97             return Thread.currentThread().getContextClassLoader()
98                    .loadClass(name);
99         else
100             return Class.forName(name);
101     }
102
103     /**
104      * Obtains the <code>java.lang.Class</code> representing this class.
105      */

106     public final Class JavaDoc getJavaClass() {
107         return javaClass;
108     }
109
110     /**
111      * Obtains the name of this class.
112      */

113     public final String JavaDoc getName() {
114         return javaClass.getName();
115     }
116
117     /**
118      * Returns true if <code>obj</code> is an instance of this class.
119      */

120     public final boolean isInstance(Object JavaDoc obj) {
121         return javaClass.isInstance(obj);
122     }
123
124     /**
125      * Creates a new instance of the class.
126      *
127      * @param args the arguments passed to the constructor.
128      */

129     public final Object JavaDoc newInstance(Object JavaDoc[] args)
130         throws CannotCreateException
131     {
132         int n = constructors.length;
133         for (int i = 0; i < n; ++i) {
134             try {
135                 return constructors[i].newInstance(args);
136             }
137             catch (IllegalArgumentException JavaDoc e) {
138                 // try again
139
}
140             catch (InstantiationException JavaDoc e) {
141                 throw new CannotCreateException(e);
142             }
143             catch (IllegalAccessException JavaDoc e) {
144                 throw new CannotCreateException(e);
145             }
146             catch (InvocationTargetException e) {
147                 throw new CannotCreateException(e);
148             }
149         }
150
151         throw new CannotCreateException("no constructor matches");
152     }
153
154     /**
155      * Is invoked when <code>static</code> fields of the base-level
156      * class are read and the runtime system intercepts it.
157      * This method simply returns the value of the field.
158      *
159      * <p>Every subclass of this class should redefine this method.
160      */

161     public Object JavaDoc trapFieldRead(String JavaDoc name) {
162         Class JavaDoc jc = getJavaClass();
163         try {
164             return jc.getField(name).get(null);
165         }
166         catch (NoSuchFieldException JavaDoc e) {
167             throw new RuntimeException JavaDoc(e.toString());
168         }
169         catch (IllegalAccessException JavaDoc e) {
170             throw new RuntimeException JavaDoc(e.toString());
171         }
172     }
173
174     /**
175      * Is invoked when <code>static</code> fields of the base-level
176      * class are modified and the runtime system intercepts it.
177      * This method simply sets the field to the given value.
178      *
179      * <p>Every subclass of this class should redefine this method.
180      */

181     public void trapFieldWrite(String JavaDoc name, Object JavaDoc value) {
182         Class JavaDoc jc = getJavaClass();
183         try {
184             jc.getField(name).set(null, value);
185         }
186         catch (NoSuchFieldException JavaDoc e) {
187             throw new RuntimeException JavaDoc(e.toString());
188         }
189         catch (IllegalAccessException JavaDoc e) {
190             throw new RuntimeException JavaDoc(e.toString());
191         }
192     }
193
194     /**
195      * Invokes a method whose name begins with
196      * <code>methodPrefix "_m_"</code> and the identifier.
197      *
198      * @exception CannotInvokeException if the invocation fails.
199      */

200     static public Object JavaDoc invoke(Object JavaDoc target, int identifier, Object JavaDoc[] args)
201         throws Throwable JavaDoc
202     {
203         Method[] allmethods = target.getClass().getMethods();
204         int n = allmethods.length;
205         String JavaDoc head = methodPrefix + identifier;
206         for (int i = 0; i < n; ++i)
207             if (allmethods[i].getName().startsWith(head)) {
208                 try {
209                     return allmethods[i].invoke(target, args);
210                 } catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
211                     throw e.getTargetException();
212                 } catch (java.lang.IllegalAccessException JavaDoc e) {
213                     throw new CannotInvokeException(e);
214                 }
215             }
216
217         throw new CannotInvokeException("cannot find a method");
218     }
219
220     /**
221      * Is invoked when <code>static</code> methods of the base-level
222      * class are called and the runtime system intercepts it.
223      * This method simply executes the intercepted method invocation
224      * with the original parameters and returns the resulting value.
225      *
226      * <p>Every subclass of this class should redefine this method.
227      */

228     public Object JavaDoc trapMethodcall(int identifier, Object JavaDoc[] args)
229         throws Throwable JavaDoc
230     {
231         try {
232             Method[] m = getReflectiveMethods();
233             return m[identifier].invoke(null, args);
234         }
235         catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
236             throw e.getTargetException();
237         }
238         catch (java.lang.IllegalAccessException JavaDoc e) {
239             throw new CannotInvokeException(e);
240         }
241     }
242
243     /**
244      * Returns an array of the methods defined on the given reflective
245      * object. This method is for the internal use only.
246      */

247     public final Method[] getReflectiveMethods() {
248         if (methods != null)
249             return methods;
250
251         Class JavaDoc baseclass = getJavaClass();
252         Method[] allmethods = baseclass.getDeclaredMethods();
253         int n = allmethods.length;
254         methods = new Method[n];
255         for (int i = 0; i < n; ++i) {
256             Method m = allmethods[i];
257             String JavaDoc mname = m.getName();
258             if (mname.startsWith(methodPrefix)) {
259                 int k = 0;
260                 for (int j = methodPrefixLen;; ++j) {
261                     char c = mname.charAt(j);
262                     if ('0' <= c && c <= '9')
263                         k = k * 10 + c - '0';
264                     else
265                         break;
266                 }
267
268                 methods[k] = m;
269             }
270         }
271
272         return methods;
273     }
274
275     /**
276      * Returns the <code>java.lang.reflect.Method</code> object representing
277      * the method specified by <code>identifier</code>.
278      *
279      * <p>Note that the actual method returned will be have an altered,
280      * reflective name i.e. <code>_m_2_..</code>.
281      *
282      * @param identifier the identifier index
283      * given to <code>trapMethodcall()</code> etc.
284      * @see Metaobject#trapMethodcall(int,Object[])
285      * @see #trapMethodcall(int,Object[])
286      */

287     public final Method getMethod(int identifier) {
288         return getReflectiveMethods()[identifier];
289     }
290
291     /**
292      * Returns the name of the method specified
293      * by <code>identifier</code>.
294      */

295     public final String JavaDoc getMethodName(int identifier) {
296         String JavaDoc mname = getReflectiveMethods()[identifier].getName();
297         int j = ClassMetaobject.methodPrefixLen;
298         for (;;) {
299             char c = mname.charAt(j++);
300             if (c < '0' || '9' < c)
301                 break;
302         }
303
304         return mname.substring(j);
305     }
306
307     /**
308      * Returns an array of <code>Class</code> objects representing the
309      * formal parameter types of the method specified
310      * by <code>identifier</code>.
311      */

312     public final Class JavaDoc[] getParameterTypes(int identifier) {
313         return getReflectiveMethods()[identifier].getParameterTypes();
314     }
315
316     /**
317      * Returns a <code>Class</code> objects representing the
318      * return type of the method specified by <code>identifier</code>.
319      */

320     public final Class JavaDoc getReturnType(int identifier) {
321         return getReflectiveMethods()[identifier].getReturnType();
322     }
323
324     /**
325      * Returns the identifier index of the method, as identified by its
326      * original name.
327      *
328      * <p>This method is useful, in conjuction with
329      * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
330      * to the original method in the reflected class (i.e. not the proxy
331      * method), using the original name of the method.
332      *
333      * <p>Written by Brett Randall and Shigeru Chiba.
334      *
335      * @param originalName The original name of the reflected method
336      * @param argTypes array of Class specifying the method signature
337      * @return the identifier index of the original method
338      * @throws NoSuchMethodException if the method does not exist
339      *
340      * @see ClassMetaobject#getMethod(int)
341      */

342     public final int getMethodIndex(String JavaDoc originalName, Class JavaDoc[] argTypes)
343         throws NoSuchMethodException JavaDoc
344     {
345         Method[] mthds = getReflectiveMethods();
346         for (int i = 0; i < mthds.length; i++) {
347             if (mthds[i] == null)
348                 continue;
349
350             // check name and parameter types match
351
if (getMethodName(i).equals(originalName)
352                 && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
353                 return i;
354         }
355
356         throw new NoSuchMethodException JavaDoc("Method " + originalName
357                                         + " not found");
358     }
359 }
360
Popular Tags