/Users/lyon/j4p/src/javassist/reflect/Metaobject.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 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.Method;
19 import java.io.Serializable;
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23
24 /**
25 * A runtime metaobject.
26 *
27 * <p>A <code>Metaobject</code> is created for
28 * every object at the base level. A different reflective object is
29 * associated with a different metaobject.
30 *
31 * <p>The metaobject intercepts method calls
32 * on the reflective object at the base-level. To change the behavior
33 * of the method calls, a subclass of <code>Metaobject</code>
34 * should be defined.
35 *
36 * @see javassist.reflect.ClassMetaobject
37 */
38 public class Metaobject implements Serializable {
39 protected ClassMetaobject classmetaobject;
40 protected Metalevel baseobject;
41 protected Method[] methods;
42
43 /**
44 * Constructs a <code>Metaobject</code>. The metaobject is
45 * constructed before the constructor is called on the base-level
46 * object.
47 *
48 * @param self the object that this metaobject is associated with.
49 * @param args the parameters passed to the constructor of
50 * <code>self</code>.
51 */
52 public Metaobject(Object self, Object[] args) {
53 baseobject = (Metalevel) self;
54 classmetaobject = baseobject._getClass();
55 methods = classmetaobject.getReflectiveMethods();
56 }
57
58 /**
59 * Constructs a <code>Metaobject</code> without initialization.
60 * If calling this constructor, a subclass should be responsible
61 * for initialization.
62 */
63 protected Metaobject() {
64 baseobject = null;
65 classmetaobject = null;
66 methods = null;
67 }
68
69 private void writeObject(ObjectOutputStream out) throws IOException {
70 out.writeObject(baseobject);
71 }
72
73 private void readObject(ObjectInputStream in)
74 throws IOException, ClassNotFoundException {
75 baseobject = (Metalevel) in.readObject();
76 classmetaobject = baseobject._getClass();
77 methods = classmetaobject.getReflectiveMethods();
78 }
79
80 /**
81 * Obtains the class metaobject associated with this metaobject.
82 *
83 * @see javassist.reflect.ClassMetaobject
84 */
85 public final ClassMetaobject getClassMetaobject() {
86 return classmetaobject;
87 }
88
89 /**
90 * Obtains the object controlled by this metaobject.
91 */
92 public final Object getObject() {
93 return baseobject;
94 }
95
96 /**
97 * Changes the object controlled by this metaobject.
98 *
99 * @param self the object
100 */
101 public final void setObject(Object self) {
102 baseobject = (Metalevel) self;
103 classmetaobject = baseobject._getClass();
104 methods = classmetaobject.getReflectiveMethods();
105
106 // call _setMetaobject() after the metaobject is settled.
107 baseobject._setMetaobject(this);
108 }
109
110 /**
111 * Returns the name of the method specified
112 * by <code>identifier</code>.
113 */
114 public final String getMethodName(int identifier) {
115 String mname = methods[identifier].getName();
116 int j = ClassMetaobject.methodPrefixLen;
117 for (; ;) {
118 char c = mname.charAt(j++);
119 if (c < '0' || '9' < c)
120 break;
121 }
122
123 return mname.substring(j);
124 }
125
126 /**
127 * Returns an array of <code>Class</code> objects representing the
128 * formal parameter types of the method specified
129 * by <code>identifier</code>.
130 */
131 public final Class[] getParameterTypes(int identifier) {
132 return methods[identifier].getParameterTypes();
133 }
134
135 /**
136 * Returns a <code>Class</code> objects representing the
137 * return type of the method specified by <code>identifier</code>.
138 */
139 public final Class getReturnType(int identifier) {
140 return methods[identifier].getReturnType();
141 }
142
143 /**
144 * Is invoked when public fields of the base-level
145 * class are read and the runtime system intercepts it.
146 * This method simply returns the value of the field.
147 *
148 * <p>Every subclass of this class should redefine this method.
149 */
150 public Object trapFieldRead(String name) {
151 Class jc = getClassMetaobject().getJavaClass();
152 try {
153 return jc.getField(name).get(getObject());
154 } catch (NoSuchFieldException e) {
155 throw new RuntimeException(e.toString());
156 } catch (IllegalAccessException e) {
157 throw new RuntimeException(e.toString());
158 }
159 }
160
161 /**
162 * Is invoked when public fields of the base-level
163 * class are modified and the runtime system intercepts it.
164 * This method simply sets the field to the given value.
165 *
166 * <p>Every subclass of this class should redefine this method.
167 */
168 public void trapFieldWrite(String name, Object value) {
169 Class jc = getClassMetaobject().getJavaClass();
170 try {
171 jc.getField(name).set(getObject(), value);
172 } catch (NoSuchFieldException e) {
173 throw new RuntimeException(e.toString());
174 } catch (IllegalAccessException e) {
175 throw new RuntimeException(e.toString());
176 }
177 }
178
179 /**
180 * Is invoked when base-level method invocation is intercepted.
181 * This method simply executes the intercepted method invocation
182 * with the original parameters and returns the resulting value.
183 *
184 * <p>Every subclass of this class should redefine this method.
185 *
186 * <p>Note: this method is not invoked if the base-level method
187 * is invoked by a constructor in the super class. For example,
188 *
189 * <ul><pre>abstract class A {
190 * abstract void initialize();
191 * A() {
192 * initialize(); // not intercepted
193 * }
194 * }
195 *
196 * class B extends A {
197 * void initialize() { System.out.println("initialize()"); }
198 * B() {
199 * super();
200 * initialize(); // intercepted
201 * }
202 * }</pre></ul>
203 *
204 * <p>if an instance of B is created,
205 * the invocation of initialize() in B is intercepted only once.
206 * The first invocation by the constructor in A is not intercepted.
207 * This is because the link between a base-level object and a
208 * metaobject is not created until the execution of a
209 * constructor of the super class finishes.
210 */
211 public Object trapMethodcall(int identifier, Object[] args)
212 throws Throwable {
213 try {
214 return methods[identifier].invoke(getObject(), args);
215 } catch (java.lang.reflect.InvocationTargetException e) {
216 throw e.getTargetException();
217 } catch (java.lang.IllegalAccessException e) {
218 throw new CannotInvokeException(e);
219 }
220 }
221 }
222