KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > reflect > Reflection


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 javassist.*;
19 import javassist.CtMethod.ConstParameter;
20
21 /**
22  * The class implementing the behavioral reflection mechanism.
23  *
24  * <p>If a class is reflective,
25  * then all the method invocations on every
26  * instance of that class are intercepted by the runtime
27  * metaobject controlling that instance. The methods inherited from the
28  * super classes are also intercepted except final methods. To intercept
29  * a final method in a super class, that super class must be also reflective.
30  *
31  * <p>To do this, the original class file representing a reflective class:
32  *
33  * <ul><pre>
34  * class Person {
35  * public int f(int i) { return i + 1; }
36  * public int value;
37  * }
38  * </pre></ul>
39  *
40  * <p>is modified so that it represents a class:
41  *
42  * <ul><pre>
43  * class Person implements Metalevel {
44  * public int _original_f(int i) { return i + 1; }
45  * public int f(int i) { <i>delegate to the metaobject</i> }
46  *
47  * public int value;
48  * public int _r_value() { <i>read "value"</i> }
49  * public void _w_value(int v) { <i>write "value"</i> }
50  *
51  * public ClassMetaobject _getClass() { <i>return a class metaobject</i> }
52  * public Metaobject _getMetaobject() { <i>return a metaobject</i> }
53  * public void _setMetaobject(Metaobject m) { <i>change a metaobject</i> }
54  * }
55  * </pre></ul>
56  *
57  * @see javassist.reflect.ClassMetaobject
58  * @see javassist.reflect.Metaobject
59  * @see javassist.reflect.Loader
60  * @see javassist.reflect.Compiler
61  */

62 public class Reflection implements Translator {
63
64     static final String JavaDoc classobjectField = "_classobject";
65     static final String JavaDoc classobjectAccessor = "_getClass";
66     static final String JavaDoc metaobjectField = "_metaobject";
67     static final String JavaDoc metaobjectGetter = "_getMetaobject";
68     static final String JavaDoc metaobjectSetter = "_setMetaobject";
69     static final String JavaDoc readPrefix = "_r_";
70     static final String JavaDoc writePrefix = "_w_";
71
72     static final String JavaDoc metaobjectClassName = "javassist.reflect.Metaobject";
73     static final String JavaDoc classMetaobjectClassName
74         = "javassist.reflect.ClassMetaobject";
75
76     protected CtMethod trapMethod, trapStaticMethod;
77     protected CtMethod trapRead, trapWrite;
78     protected CtClass[] readParam;
79
80     protected ClassPool classPool;
81     protected CodeConverter converter;
82
83     private boolean isExcluded(String JavaDoc name) {
84         return name.startsWith(ClassMetaobject.methodPrefix)
85             || name.equals(classobjectAccessor)
86             || name.equals(metaobjectSetter)
87             || name.equals(metaobjectGetter)
88             || name.startsWith(readPrefix)
89             || name.startsWith(writePrefix);
90     }
91
92     /**
93      * Constructs a new <code>Reflection</code> object.
94      */

95     public Reflection() {
96         classPool = null;
97         converter = new CodeConverter();
98     }
99
100     /**
101      * Initializes the object.
102      */

103     public void start(ClassPool pool) throws NotFoundException {
104         classPool = pool;
105         final String JavaDoc msg
106             = "javassist.reflect.Sample is not found or broken.";
107         try {
108             CtClass c = classPool.get("javassist.reflect.Sample");
109             trapMethod = c.getDeclaredMethod("trap");
110             trapStaticMethod = c.getDeclaredMethod("trapStatic");
111             trapRead = c.getDeclaredMethod("trapRead");
112             trapWrite = c.getDeclaredMethod("trapWrite");
113             readParam
114                 = new CtClass[] { classPool.get("java.lang.Object") };
115         }
116         catch (NotFoundException e) {
117             throw new RuntimeException JavaDoc(msg);
118         }
119     }
120
121     /**
122      * Inserts hooks for intercepting accesses to the fields declared
123      * in reflective classes.
124      */

125     public void onLoad(ClassPool pool, String JavaDoc classname)
126         throws CannotCompileException, NotFoundException
127     {
128         CtClass clazz = pool.get(classname);
129         clazz.instrument(converter);
130     }
131
132     /**
133      * Produces a reflective class.
134      * If the super class is also made reflective, it must be done
135      * before the sub class.
136      *
137      * @param classname the name of the reflective class
138      * @param metaobject the class name of metaobjects.
139      * @param metaclass the class name of the class metaobject.
140      * @return <code>false</code> if the class is already reflective.
141      *
142      * @see javassist.reflect.Metaobject
143      * @see javassist.reflect.ClassMetaobject
144      */

145     public boolean makeReflective(String JavaDoc classname,
146                                   String JavaDoc metaobject, String JavaDoc metaclass)
147         throws CannotCompileException, NotFoundException
148     {
149         return makeReflective(classPool.get(classname),
150                               classPool.get(metaobject),
151                               classPool.get(metaclass));
152     }
153
154     /**
155      * Produces a reflective class.
156      * If the super class is also made reflective, it must be done
157      * before the sub class.
158      *
159      * @param clazz the reflective class.
160      * @param metaobject the class of metaobjects.
161      * It must be a subclass of
162      * <code>Metaobject</code>.
163      * @param metaclass the class of the class metaobject.
164      * It must be a subclass of
165      * <code>ClassMetaobject</code>.
166      * @return <code>false</code> if the class is already reflective.
167      *
168      * @see javassist.reflect.Metaobject
169      * @see javassist.reflect.ClassMetaobject
170      */

171     public boolean makeReflective(Class JavaDoc clazz,
172                                   Class JavaDoc metaobject, Class JavaDoc metaclass)
173         throws CannotCompileException, NotFoundException
174     {
175         return makeReflective(clazz.getName(), metaobject.getName(),
176                               metaclass.getName());
177     }
178
179     /**
180      * Produces a reflective class. It modifies the given
181      * <code>CtClass</code> object and makes it reflective.
182      * If the super class is also made reflective, it must be done
183      * before the sub class.
184      *
185      * @param clazz the reflective class.
186      * @param metaobject the class of metaobjects.
187      * It must be a subclass of
188      * <code>Metaobject</code>.
189      * @param metaclass the class of the class metaobject.
190      * It must be a subclass of
191      * <code>ClassMetaobject</code>.
192      * @return <code>false</code> if the class is already reflective.
193      *
194      * @see javassist.reflect.Metaobject
195      * @see javassist.reflect.ClassMetaobject
196      */

197     public boolean makeReflective(CtClass clazz,
198                                   CtClass metaobject, CtClass metaclass)
199         throws CannotCompileException, CannotReflectException,
200                NotFoundException
201     {
202         if (clazz.isInterface())
203             throw new CannotReflectException(
204                     "Cannot reflect an interface: " + clazz.getName());
205
206         if (clazz.subclassOf(classPool.get(classMetaobjectClassName)))
207             throw new CannotReflectException(
208                 "Cannot reflect a subclass of ClassMetaobject: "
209                 + clazz.getName());
210
211         if (clazz.subclassOf(classPool.get(metaobjectClassName)))
212             throw new CannotReflectException(
213                 "Cannot reflect a subclass of Metaobject: "
214                 + clazz.getName());
215
216         registerReflectiveClass(clazz);
217         return modifyClassfile(clazz, metaobject, metaclass);
218     }
219
220     /**
221      * Registers a reflective class. The field accesses to the instances
222      * of this class are instrumented.
223      */

224     private void registerReflectiveClass(CtClass clazz) {
225         CtField[] fs = clazz.getDeclaredFields();
226         for (int i = 0; i < fs.length; ++i) {
227             CtField f = fs[i];
228             int mod = f.getModifiers();
229             if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
230                 String JavaDoc name = f.getName();
231                 converter.replaceFieldRead(f, clazz, readPrefix + name);
232                 converter.replaceFieldWrite(f, clazz, writePrefix + name);
233             }
234         }
235     }
236
237     private boolean modifyClassfile(CtClass clazz, CtClass metaobject,
238                                     CtClass metaclass)
239         throws CannotCompileException, NotFoundException
240     {
241         if (clazz.getAttribute("Reflective") != null)
242             return false; // this is already reflective.
243
else
244             clazz.setAttribute("Reflective", new byte[0]);
245
246         CtClass mlevel = classPool.get("javassist.reflect.Metalevel");
247         boolean addMeta = !clazz.subtypeOf(mlevel);
248         if (addMeta)
249             clazz.addInterface(mlevel);
250
251         processMethods(clazz, addMeta);
252         processFields(clazz);
253
254         CtField f;
255         if (addMeta) {
256             f = new CtField(classPool.get("javassist.reflect.Metaobject"),
257                             metaobjectField, clazz);
258             f.setModifiers(Modifier.PROTECTED);
259             clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject));
260
261             clazz.addMethod(CtNewMethod.getter(metaobjectGetter, f));
262             clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f));
263         }
264
265         f = new CtField(classPool.get("javassist.reflect.ClassMetaobject"),
266                         classobjectField, clazz);
267         f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
268         clazz.addField(f, CtField.Initializer.byNew(metaclass,
269                                         new String JavaDoc[] { clazz.getName() }));
270
271         clazz.addMethod(CtNewMethod.getter(classobjectAccessor, f));
272         return true;
273     }
274
275     private void processMethods(CtClass clazz, boolean dontSearch)
276         throws CannotCompileException, NotFoundException
277     {
278         CtMethod[] ms = clazz.getMethods();
279         int identifier = 0;
280         for (int i = 0; i < ms.length; ++i) {
281             CtMethod m = ms[i];
282             int mod = m.getModifiers();
283             if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod))
284                 processMethods0(mod, clazz, m, i, dontSearch);
285         }
286     }
287
288     private void processMethods0(int mod, CtClass clazz,
289                         CtMethod m, int identifier, boolean dontSearch)
290         throws CannotCompileException, NotFoundException
291     {
292         CtMethod body;
293         String JavaDoc name = m.getName();
294
295         if (isExcluded(name)) // internally-used method inherited
296
return; // from a reflective class.
297

298         CtMethod m2;
299         if (m.getDeclaringClass() == clazz) {
300             if (Modifier.isNative(mod))
301                 return;
302
303             m2 = m;
304             if (Modifier.isFinal(mod)) {
305                 mod &= ~Modifier.FINAL;
306                 m2.setModifiers(mod);
307             }
308         }
309         else {
310             if (Modifier.isFinal(mod))
311                 return;
312
313             mod &= ~Modifier.NATIVE;
314             m2 = CtNewMethod.delegator(findOriginal(m, dontSearch), clazz);
315             m2.setModifiers(mod);
316             clazz.addMethod(m2);
317         }
318
319         m2.setName(ClassMetaobject.methodPrefix + identifier
320                       + "_" + name);
321
322         if (Modifier.isStatic(mod))
323             body = trapStaticMethod;
324         else
325             body = trapMethod;
326
327         CtMethod wmethod
328             = CtNewMethod.wrapped(m.getReturnType(), name,
329                                   m.getParameterTypes(), m.getExceptionTypes(),
330                                   body, ConstParameter.integer(identifier),
331                                   clazz);
332         wmethod.setModifiers(mod);
333         clazz.addMethod(wmethod);
334     }
335
336     private CtMethod findOriginal(CtMethod m, boolean dontSearch)
337         throws NotFoundException
338     {
339         if (dontSearch)
340             return m;
341
342         String JavaDoc name = m.getName();
343         CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods();
344         for (int i = 0; i < ms.length; ++i) {
345             String JavaDoc orgName = ms[i].getName();
346             if (orgName.endsWith(name)
347                 && orgName.startsWith(ClassMetaobject.methodPrefix)
348                 && ms[i].getSignature().equals(m.getSignature()))
349                 return ms[i];
350         }
351
352         return m;
353     }
354
355     private void processFields(CtClass clazz)
356         throws CannotCompileException, NotFoundException
357     {
358         CtField[] fs = clazz.getDeclaredFields();
359         for (int i = 0; i < fs.length; ++i) {
360             CtField f = fs[i];
361             int mod = f.getModifiers();
362             if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
363                 mod |= Modifier.STATIC;
364                 String JavaDoc name = f.getName();
365                 CtClass ftype = f.getType();
366                 CtMethod wmethod
367                     = CtNewMethod.wrapped(ftype, readPrefix + name,
368                                           readParam, null, trapRead,
369                                           ConstParameter.string(name),
370                                           clazz);
371                 wmethod.setModifiers(mod);
372                 clazz.addMethod(wmethod);
373                 CtClass[] writeParam = new CtClass[2];
374                 writeParam[0] = classPool.get("java.lang.Object");
375                 writeParam[1] = ftype;
376                 wmethod = CtNewMethod.wrapped(CtClass.voidType,
377                                 writePrefix + name,
378                                 writeParam, null, trapWrite,
379                                 ConstParameter.string(name), clazz);
380                 wmethod.setModifiers(mod);
381                 clazz.addMethod(wmethod);
382             }
383         }
384     }
385 }
386
Popular Tags