/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