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