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