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 java.lang.reflect.Method;
019: import java.io.Serializable;
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023:
024: /**
025: * A runtime metaobject.
026: *
027: * <p>A <code>Metaobject</code> is created for
028: * every object at the base level. A different reflective object is
029: * associated with a different metaobject.
030: *
031: * <p>The metaobject intercepts method calls
032: * on the reflective object at the base-level. To change the behavior
033: * of the method calls, a subclass of <code>Metaobject</code>
034: * should be defined.
035: *
036: * <p>To obtain a metaobject, calls <code>_getMetaobject()</code>
037: * on a reflective object. For example,
038: *
039: * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject();
040: * </pre></ul>
041: *
042: * @see javassist.tools.reflect.ClassMetaobject
043: * @see javassist.tools.reflect.Metalevel
044: */
045: public class Metaobject implements Serializable {
046: protected ClassMetaobject classmetaobject;
047: protected Metalevel baseobject;
048: protected Method[] methods;
049:
050: /**
051: * Constructs a <code>Metaobject</code>. The metaobject is
052: * constructed before the constructor is called on the base-level
053: * object.
054: *
055: * @param self the object that this metaobject is associated with.
056: * @param args the parameters passed to the constructor of
057: * <code>self</code>.
058: */
059: public Metaobject(Object self, Object[] args) {
060: baseobject = (Metalevel) self;
061: classmetaobject = baseobject._getClass();
062: methods = classmetaobject.getReflectiveMethods();
063: }
064:
065: /**
066: * Constructs a <code>Metaobject</code> without initialization.
067: * If calling this constructor, a subclass should be responsible
068: * for initialization.
069: */
070: protected Metaobject() {
071: baseobject = null;
072: classmetaobject = null;
073: methods = null;
074: }
075:
076: private void writeObject(ObjectOutputStream out) throws IOException {
077: out.writeObject(baseobject);
078: }
079:
080: private void readObject(ObjectInputStream in) throws IOException,
081: ClassNotFoundException {
082: baseobject = (Metalevel) in.readObject();
083: classmetaobject = baseobject._getClass();
084: methods = classmetaobject.getReflectiveMethods();
085: }
086:
087: /**
088: * Obtains the class metaobject associated with this metaobject.
089: *
090: * @see javassist.tools.reflect.ClassMetaobject
091: */
092: public final ClassMetaobject getClassMetaobject() {
093: return classmetaobject;
094: }
095:
096: /**
097: * Obtains the object controlled by this metaobject.
098: */
099: public final Object getObject() {
100: return baseobject;
101: }
102:
103: /**
104: * Changes the object controlled by this metaobject.
105: *
106: * @param self the object
107: */
108: public final void setObject(Object self) {
109: baseobject = (Metalevel) self;
110: classmetaobject = baseobject._getClass();
111: methods = classmetaobject.getReflectiveMethods();
112:
113: // call _setMetaobject() after the metaobject is settled.
114: baseobject._setMetaobject(this );
115: }
116:
117: /**
118: * Returns the name of the method specified
119: * by <code>identifier</code>.
120: */
121: public final String getMethodName(int identifier) {
122: String mname = methods[identifier].getName();
123: int j = ClassMetaobject.methodPrefixLen;
124: for (;;) {
125: char c = mname.charAt(j++);
126: if (c < '0' || '9' < c)
127: break;
128: }
129:
130: return mname.substring(j);
131: }
132:
133: /**
134: * Returns an array of <code>Class</code> objects representing the
135: * formal parameter types of the method specified
136: * by <code>identifier</code>.
137: */
138: public final Class[] getParameterTypes(int identifier) {
139: return methods[identifier].getParameterTypes();
140: }
141:
142: /**
143: * Returns a <code>Class</code> objects representing the
144: * return type of the method specified by <code>identifier</code>.
145: */
146: public final Class getReturnType(int identifier) {
147: return methods[identifier].getReturnType();
148: }
149:
150: /**
151: * Is invoked when public fields of the base-level
152: * class are read and the runtime system intercepts it.
153: * This method simply returns the value of the field.
154: *
155: * <p>Every subclass of this class should redefine this method.
156: */
157: public Object trapFieldRead(String name) {
158: Class jc = getClassMetaobject().getJavaClass();
159: try {
160: return jc.getField(name).get(getObject());
161: } catch (NoSuchFieldException e) {
162: throw new RuntimeException(e.toString());
163: } catch (IllegalAccessException e) {
164: throw new RuntimeException(e.toString());
165: }
166: }
167:
168: /**
169: * Is invoked when public fields of the base-level
170: * class are modified and the runtime system intercepts it.
171: * This method simply sets the field to the given value.
172: *
173: * <p>Every subclass of this class should redefine this method.
174: */
175: public void trapFieldWrite(String name, Object value) {
176: Class jc = getClassMetaobject().getJavaClass();
177: try {
178: jc.getField(name).set(getObject(), value);
179: } catch (NoSuchFieldException e) {
180: throw new RuntimeException(e.toString());
181: } catch (IllegalAccessException e) {
182: throw new RuntimeException(e.toString());
183: }
184: }
185:
186: /**
187: * Is invoked when base-level method invocation is intercepted.
188: * This method simply executes the intercepted method invocation
189: * with the original parameters and returns the resulting value.
190: *
191: * <p>Every subclass of this class should redefine this method.
192: *
193: * <p>Note: this method is not invoked if the base-level method
194: * is invoked by a constructor in the super class. For example,
195: *
196: * <ul><pre>abstract class A {
197: * abstract void initialize();
198: * A() {
199: * initialize(); // not intercepted
200: * }
201: * }
202: *
203: * class B extends A {
204: * void initialize() { System.out.println("initialize()"); }
205: * B() {
206: * super();
207: * initialize(); // intercepted
208: * }
209: * }</pre></ul>
210: *
211: * <p>if an instance of B is created,
212: * the invocation of initialize() in B is intercepted only once.
213: * The first invocation by the constructor in A is not intercepted.
214: * This is because the link between a base-level object and a
215: * metaobject is not created until the execution of a
216: * constructor of the super class finishes.
217: */
218: public Object trapMethodcall(int identifier, Object[] args)
219: throws Throwable {
220: try {
221: return methods[identifier].invoke(getObject(), args);
222: } catch (java.lang.reflect.InvocationTargetException e) {
223: throw e.getTargetException();
224: } catch (java.lang.IllegalAccessException e) {
225: throw new CannotInvokeException(e);
226: }
227: }
228: }
|