001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.tools.reflect;
017:
018: import javassist.*;
019: import javassist.CtMethod.ConstParameter;
020:
021: /**
022: * The class implementing the behavioral reflection mechanism.
023: *
024: * <p>If a class is reflective,
025: * then all the method invocations on every
026: * instance of that class are intercepted by the runtime
027: * metaobject controlling that instance. The methods inherited from the
028: * super classes are also intercepted except final methods. To intercept
029: * a final method in a super class, that super class must be also reflective.
030: *
031: * <p>To do this, the original class file representing a reflective class:
032: *
033: * <ul><pre>
034: * class Person {
035: * public int f(int i) { return i + 1; }
036: * public int value;
037: * }
038: * </pre></ul>
039: *
040: * <p>is modified so that it represents a class:
041: *
042: * <ul><pre>
043: * class Person implements Metalevel {
044: * public int _original_f(int i) { return i + 1; }
045: * public int f(int i) { <i>delegate to the metaobject</i> }
046: *
047: * public int value;
048: * public int _r_value() { <i>read "value"</i> }
049: * public void _w_value(int v) { <i>write "value"</i> }
050: *
051: * public ClassMetaobject _getClass() { <i>return a class metaobject</i> }
052: * public Metaobject _getMetaobject() { <i>return a metaobject</i> }
053: * public void _setMetaobject(Metaobject m) { <i>change a metaobject</i> }
054: * }
055: * </pre></ul>
056: *
057: * @see javassist.tools.reflect.ClassMetaobject
058: * @see javassist.tools.reflect.Metaobject
059: * @see javassist.tools.reflect.Loader
060: * @see javassist.tools.reflect.Compiler
061: */
062: public class Reflection implements Translator {
063:
064: static final String classobjectField = "_classobject";
065: static final String classobjectAccessor = "_getClass";
066: static final String metaobjectField = "_metaobject";
067: static final String metaobjectGetter = "_getMetaobject";
068: static final String metaobjectSetter = "_setMetaobject";
069: static final String readPrefix = "_r_";
070: static final String writePrefix = "_w_";
071:
072: static final String metaobjectClassName = "javassist.tools.reflect.Metaobject";
073: static final String classMetaobjectClassName = "javassist.tools.reflect.ClassMetaobject";
074:
075: protected CtMethod trapMethod, trapStaticMethod;
076: protected CtMethod trapRead, trapWrite;
077: protected CtClass[] readParam;
078:
079: protected ClassPool classPool;
080: protected CodeConverter converter;
081:
082: private boolean isExcluded(String name) {
083: return name.startsWith(ClassMetaobject.methodPrefix)
084: || name.equals(classobjectAccessor)
085: || name.equals(metaobjectSetter)
086: || name.equals(metaobjectGetter)
087: || name.startsWith(readPrefix)
088: || name.startsWith(writePrefix);
089: }
090:
091: /**
092: * Constructs a new <code>Reflection</code> object.
093: */
094: public Reflection() {
095: classPool = null;
096: converter = new CodeConverter();
097: }
098:
099: /**
100: * Initializes the object.
101: */
102: public void start(ClassPool pool) throws NotFoundException {
103: classPool = pool;
104: final String msg = "javassist.tools.reflect.Sample is not found or broken.";
105: try {
106: CtClass c = classPool.get("javassist.tools.reflect.Sample");
107: trapMethod = c.getDeclaredMethod("trap");
108: trapStaticMethod = c.getDeclaredMethod("trapStatic");
109: trapRead = c.getDeclaredMethod("trapRead");
110: trapWrite = c.getDeclaredMethod("trapWrite");
111: readParam = new CtClass[] { classPool
112: .get("java.lang.Object") };
113: } catch (NotFoundException e) {
114: throw new RuntimeException(msg);
115: }
116: }
117:
118: /**
119: * Inserts hooks for intercepting accesses to the fields declared
120: * in reflective classes.
121: */
122: public void onLoad(ClassPool pool, String classname)
123: throws CannotCompileException, NotFoundException {
124: CtClass clazz = pool.get(classname);
125: clazz.instrument(converter);
126: }
127:
128: /**
129: * Produces a reflective class.
130: * If the super class is also made reflective, it must be done
131: * before the sub class.
132: *
133: * @param classname the name of the reflective class
134: * @param metaobject the class name of metaobjects.
135: * @param metaclass the class name of the class metaobject.
136: * @return <code>false</code> if the class is already reflective.
137: *
138: * @see javassist.tools.reflect.Metaobject
139: * @see javassist.tools.reflect.ClassMetaobject
140: */
141: public boolean makeReflective(String classname, String metaobject,
142: String metaclass) throws CannotCompileException,
143: NotFoundException {
144: return makeReflective(classPool.get(classname), classPool
145: .get(metaobject), classPool.get(metaclass));
146: }
147:
148: /**
149: * Produces a reflective class.
150: * If the super class is also made reflective, it must be done
151: * before the sub class.
152: *
153: * @param clazz the reflective class.
154: * @param metaobject the class of metaobjects.
155: * It must be a subclass of
156: * <code>Metaobject</code>.
157: * @param metaclass the class of the class metaobject.
158: * It must be a subclass of
159: * <code>ClassMetaobject</code>.
160: * @return <code>false</code> if the class is already reflective.
161: *
162: * @see javassist.tools.reflect.Metaobject
163: * @see javassist.tools.reflect.ClassMetaobject
164: */
165: public boolean makeReflective(Class clazz, Class metaobject,
166: Class metaclass) throws CannotCompileException,
167: NotFoundException {
168: return makeReflective(clazz.getName(), metaobject.getName(),
169: metaclass.getName());
170: }
171:
172: /**
173: * Produces a reflective class. It modifies the given
174: * <code>CtClass</code> object and makes it reflective.
175: * If the super class is also made reflective, it must be done
176: * before the sub class.
177: *
178: * @param clazz the reflective class.
179: * @param metaobject the class of metaobjects.
180: * It must be a subclass of
181: * <code>Metaobject</code>.
182: * @param metaclass the class of the class metaobject.
183: * It must be a subclass of
184: * <code>ClassMetaobject</code>.
185: * @return <code>false</code> if the class is already reflective.
186: *
187: * @see javassist.tools.reflect.Metaobject
188: * @see javassist.tools.reflect.ClassMetaobject
189: */
190: public boolean makeReflective(CtClass clazz, CtClass metaobject,
191: CtClass metaclass) throws CannotCompileException,
192: CannotReflectException, NotFoundException {
193: if (clazz.isInterface())
194: throw new CannotReflectException(
195: "Cannot reflect an interface: " + clazz.getName());
196:
197: if (clazz.subclassOf(classPool.get(classMetaobjectClassName)))
198: throw new CannotReflectException(
199: "Cannot reflect a subclass of ClassMetaobject: "
200: + clazz.getName());
201:
202: if (clazz.subclassOf(classPool.get(metaobjectClassName)))
203: throw new CannotReflectException(
204: "Cannot reflect a subclass of Metaobject: "
205: + clazz.getName());
206:
207: registerReflectiveClass(clazz);
208: return modifyClassfile(clazz, metaobject, metaclass);
209: }
210:
211: /**
212: * Registers a reflective class. The field accesses to the instances
213: * of this class are instrumented.
214: */
215: private void registerReflectiveClass(CtClass clazz) {
216: CtField[] fs = clazz.getDeclaredFields();
217: for (int i = 0; i < fs.length; ++i) {
218: CtField f = fs[i];
219: int mod = f.getModifiers();
220: if ((mod & Modifier.PUBLIC) != 0
221: && (mod & Modifier.FINAL) == 0) {
222: String name = f.getName();
223: converter.replaceFieldRead(f, clazz, readPrefix + name);
224: converter.replaceFieldWrite(f, clazz, writePrefix
225: + name);
226: }
227: }
228: }
229:
230: private boolean modifyClassfile(CtClass clazz, CtClass metaobject,
231: CtClass metaclass) throws CannotCompileException,
232: NotFoundException {
233: if (clazz.getAttribute("Reflective") != null)
234: return false; // this is already reflective.
235: else
236: clazz.setAttribute("Reflective", new byte[0]);
237:
238: CtClass mlevel = classPool
239: .get("javassist.tools.reflect.Metalevel");
240: boolean addMeta = !clazz.subtypeOf(mlevel);
241: if (addMeta)
242: clazz.addInterface(mlevel);
243:
244: processMethods(clazz, addMeta);
245: processFields(clazz);
246:
247: CtField f;
248: if (addMeta) {
249: f = new CtField(classPool
250: .get("javassist.tools.reflect.Metaobject"),
251: metaobjectField, clazz);
252: f.setModifiers(Modifier.PROTECTED);
253: clazz.addField(f, CtField.Initializer
254: .byNewWithParams(metaobject));
255:
256: clazz.addMethod(CtNewMethod.getter(metaobjectGetter, f));
257: clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f));
258: }
259:
260: f = new CtField(classPool
261: .get("javassist.tools.reflect.ClassMetaobject"),
262: classobjectField, clazz);
263: f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
264: clazz.addField(f, CtField.Initializer.byNew(metaclass,
265: new String[] { clazz.getName() }));
266:
267: clazz.addMethod(CtNewMethod.getter(classobjectAccessor, f));
268: return true;
269: }
270:
271: private void processMethods(CtClass clazz, boolean dontSearch)
272: throws CannotCompileException, NotFoundException {
273: CtMethod[] ms = clazz.getMethods();
274: for (int i = 0; i < ms.length; ++i) {
275: CtMethod m = ms[i];
276: int mod = m.getModifiers();
277: if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod))
278: processMethods0(mod, clazz, m, i, dontSearch);
279: }
280: }
281:
282: private void processMethods0(int mod, CtClass clazz, CtMethod m,
283: int identifier, boolean dontSearch)
284: throws CannotCompileException, NotFoundException {
285: CtMethod body;
286: String name = m.getName();
287:
288: if (isExcluded(name)) // internally-used method inherited
289: return; // from a reflective class.
290:
291: CtMethod m2;
292: if (m.getDeclaringClass() == clazz) {
293: if (Modifier.isNative(mod))
294: return;
295:
296: m2 = m;
297: if (Modifier.isFinal(mod)) {
298: mod &= ~Modifier.FINAL;
299: m2.setModifiers(mod);
300: }
301: } else {
302: if (Modifier.isFinal(mod))
303: return;
304:
305: mod &= ~Modifier.NATIVE;
306: m2 = CtNewMethod.delegator(findOriginal(m, dontSearch),
307: clazz);
308: m2.setModifiers(mod);
309: clazz.addMethod(m2);
310: }
311:
312: m2.setName(ClassMetaobject.methodPrefix + identifier + "_"
313: + name);
314:
315: if (Modifier.isStatic(mod))
316: body = trapStaticMethod;
317: else
318: body = trapMethod;
319:
320: CtMethod wmethod = CtNewMethod.wrapped(m.getReturnType(), name,
321: m.getParameterTypes(), m.getExceptionTypes(), body,
322: ConstParameter.integer(identifier), clazz);
323: wmethod.setModifiers(mod);
324: clazz.addMethod(wmethod);
325: }
326:
327: private CtMethod findOriginal(CtMethod m, boolean dontSearch)
328: throws NotFoundException {
329: if (dontSearch)
330: return m;
331:
332: String name = m.getName();
333: CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods();
334: for (int i = 0; i < ms.length; ++i) {
335: String orgName = ms[i].getName();
336: if (orgName.endsWith(name)
337: && orgName.startsWith(ClassMetaobject.methodPrefix)
338: && ms[i].getSignature().equals(m.getSignature()))
339: return ms[i];
340: }
341:
342: return m;
343: }
344:
345: private void processFields(CtClass clazz)
346: throws CannotCompileException, NotFoundException {
347: CtField[] fs = clazz.getDeclaredFields();
348: for (int i = 0; i < fs.length; ++i) {
349: CtField f = fs[i];
350: int mod = f.getModifiers();
351: if ((mod & Modifier.PUBLIC) != 0
352: && (mod & Modifier.FINAL) == 0) {
353: mod |= Modifier.STATIC;
354: String name = f.getName();
355: CtClass ftype = f.getType();
356: CtMethod wmethod = CtNewMethod.wrapped(ftype,
357: readPrefix + name, readParam, null, trapRead,
358: ConstParameter.string(name), clazz);
359: wmethod.setModifiers(mod);
360: clazz.addMethod(wmethod);
361: CtClass[] writeParam = new CtClass[2];
362: writeParam[0] = classPool.get("java.lang.Object");
363: writeParam[1] = ftype;
364: wmethod = CtNewMethod.wrapped(CtClass.voidType,
365: writePrefix + name, writeParam, null,
366: trapWrite, ConstParameter.string(name), clazz);
367: wmethod.setModifiers(mod);
368: clazz.addMethod(wmethod);
369: }
370: }
371: }
372: }
|