You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Metaobject.java 7.6KB

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