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.

ClassMetaobject.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2005 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. package javassist.tools.reflect;
  16. import java.lang.reflect.*;
  17. import java.util.Arrays;
  18. import java.io.Serializable;
  19. import java.io.IOException;
  20. import java.io.ObjectInputStream;
  21. import java.io.ObjectOutputStream;
  22. /**
  23. * A runtime class metaobject.
  24. *
  25. * <p>A <code>ClassMetaobject</code> is created for every
  26. * class of reflective objects. It can be used to hold values
  27. * shared among the reflective objects of the same class.
  28. *
  29. * <p>To obtain a class metaobject, calls <code>_getClass()</code>
  30. * on a reflective object. For example,
  31. *
  32. * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
  33. * </pre></ul>
  34. *
  35. * @see javassist.tools.reflect.Metaobject
  36. * @see javassist.tools.reflect.Metalevel
  37. */
  38. public class ClassMetaobject implements Serializable {
  39. /**
  40. * The base-level methods controlled by a metaobject
  41. * are renamed so that they begin with
  42. * <code>methodPrefix "_m_"</code>.
  43. */
  44. static final String methodPrefix = "_m_";
  45. static final int methodPrefixLen = 3;
  46. private Class javaClass;
  47. private Constructor[] constructors;
  48. private Method[] methods;
  49. /**
  50. * Specifies how a <code>java.lang.Class</code> object is loaded.
  51. *
  52. * <p>If true, it is loaded by:
  53. * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
  54. * <p>If false, it is loaded by <code>Class.forName()</code>.
  55. * The default value is false.
  56. */
  57. public static boolean useContextClassLoader = false;
  58. /**
  59. * Constructs a <code>ClassMetaobject</code>.
  60. *
  61. * @param params <code>params[0]</code> is the name of the class
  62. * of the reflective objects.
  63. */
  64. public ClassMetaobject(String[] params)
  65. {
  66. try {
  67. javaClass = getClassObject(params[0]);
  68. }
  69. catch (ClassNotFoundException e) {
  70. javaClass = null;
  71. }
  72. constructors = javaClass.getConstructors();
  73. methods = null;
  74. }
  75. private void writeObject(ObjectOutputStream out) throws IOException {
  76. out.writeUTF(javaClass.getName());
  77. }
  78. private void readObject(ObjectInputStream in)
  79. throws IOException, ClassNotFoundException
  80. {
  81. javaClass = getClassObject(in.readUTF());
  82. constructors = javaClass.getConstructors();
  83. methods = null;
  84. }
  85. private Class getClassObject(String name) throws ClassNotFoundException {
  86. if (useContextClassLoader)
  87. return Thread.currentThread().getContextClassLoader()
  88. .loadClass(name);
  89. else
  90. return Class.forName(name);
  91. }
  92. /**
  93. * Obtains the <code>java.lang.Class</code> representing this class.
  94. */
  95. public final Class getJavaClass() {
  96. return javaClass;
  97. }
  98. /**
  99. * Obtains the name of this class.
  100. */
  101. public final String getName() {
  102. return javaClass.getName();
  103. }
  104. /**
  105. * Returns true if <code>obj</code> is an instance of this class.
  106. */
  107. public final boolean isInstance(Object obj) {
  108. return javaClass.isInstance(obj);
  109. }
  110. /**
  111. * Creates a new instance of the class.
  112. *
  113. * @param args the arguments passed to the constructor.
  114. */
  115. public final Object newInstance(Object[] args)
  116. throws CannotCreateException
  117. {
  118. int n = constructors.length;
  119. for (int i = 0; i < n; ++i) {
  120. try {
  121. return constructors[i].newInstance(args);
  122. }
  123. catch (IllegalArgumentException e) {
  124. // try again
  125. }
  126. catch (InstantiationException e) {
  127. throw new CannotCreateException(e);
  128. }
  129. catch (IllegalAccessException e) {
  130. throw new CannotCreateException(e);
  131. }
  132. catch (InvocationTargetException e) {
  133. throw new CannotCreateException(e);
  134. }
  135. }
  136. throw new CannotCreateException("no constructor matches");
  137. }
  138. /**
  139. * Is invoked when <code>static</code> fields of the base-level
  140. * class are read and the runtime system intercepts it.
  141. * This method simply returns the value of the field.
  142. *
  143. * <p>Every subclass of this class should redefine this method.
  144. */
  145. public Object trapFieldRead(String name) {
  146. Class jc = getJavaClass();
  147. try {
  148. return jc.getField(name).get(null);
  149. }
  150. catch (NoSuchFieldException e) {
  151. throw new RuntimeException(e.toString());
  152. }
  153. catch (IllegalAccessException e) {
  154. throw new RuntimeException(e.toString());
  155. }
  156. }
  157. /**
  158. * Is invoked when <code>static</code> fields of the base-level
  159. * class are modified and the runtime system intercepts it.
  160. * This method simply sets the field to the given value.
  161. *
  162. * <p>Every subclass of this class should redefine this method.
  163. */
  164. public void trapFieldWrite(String name, Object value) {
  165. Class jc = getJavaClass();
  166. try {
  167. jc.getField(name).set(null, value);
  168. }
  169. catch (NoSuchFieldException e) {
  170. throw new RuntimeException(e.toString());
  171. }
  172. catch (IllegalAccessException e) {
  173. throw new RuntimeException(e.toString());
  174. }
  175. }
  176. /**
  177. * Invokes a method whose name begins with
  178. * <code>methodPrefix "_m_"</code> and the identifier.
  179. *
  180. * @exception CannotInvokeException if the invocation fails.
  181. */
  182. static public Object invoke(Object target, int identifier, Object[] args)
  183. throws Throwable
  184. {
  185. Method[] allmethods = target.getClass().getMethods();
  186. int n = allmethods.length;
  187. String head = methodPrefix + identifier;
  188. for (int i = 0; i < n; ++i)
  189. if (allmethods[i].getName().startsWith(head)) {
  190. try {
  191. return allmethods[i].invoke(target, args);
  192. } catch (java.lang.reflect.InvocationTargetException e) {
  193. throw e.getTargetException();
  194. } catch (java.lang.IllegalAccessException e) {
  195. throw new CannotInvokeException(e);
  196. }
  197. }
  198. throw new CannotInvokeException("cannot find a method");
  199. }
  200. /**
  201. * Is invoked when <code>static</code> methods of the base-level
  202. * class are called and the runtime system intercepts it.
  203. * This method simply executes the intercepted method invocation
  204. * with the original parameters and returns the resulting value.
  205. *
  206. * <p>Every subclass of this class should redefine this method.
  207. */
  208. public Object trapMethodcall(int identifier, Object[] args)
  209. throws Throwable
  210. {
  211. try {
  212. Method[] m = getReflectiveMethods();
  213. return m[identifier].invoke(null, args);
  214. }
  215. catch (java.lang.reflect.InvocationTargetException e) {
  216. throw e.getTargetException();
  217. }
  218. catch (java.lang.IllegalAccessException e) {
  219. throw new CannotInvokeException(e);
  220. }
  221. }
  222. /**
  223. * Returns an array of the methods defined on the given reflective
  224. * object. This method is for the internal use only.
  225. */
  226. public final Method[] getReflectiveMethods() {
  227. if (methods != null)
  228. return methods;
  229. Class baseclass = getJavaClass();
  230. Method[] allmethods = baseclass.getDeclaredMethods();
  231. int n = allmethods.length;
  232. int[] index = new int[n];
  233. int max = 0;
  234. for (int i = 0; i < n; ++i) {
  235. Method m = allmethods[i];
  236. String mname = m.getName();
  237. if (mname.startsWith(methodPrefix)) {
  238. int k = 0;
  239. for (int j = methodPrefixLen;; ++j) {
  240. char c = mname.charAt(j);
  241. if ('0' <= c && c <= '9')
  242. k = k * 10 + c - '0';
  243. else
  244. break;
  245. }
  246. index[i] = ++k;
  247. if (k > max)
  248. max = k;
  249. }
  250. }
  251. methods = new Method[max];
  252. for (int i = 0; i < n; ++i)
  253. if (index[i] > 0)
  254. methods[index[i] - 1] = allmethods[i];
  255. return methods;
  256. }
  257. /**
  258. * Returns the <code>java.lang.reflect.Method</code> object representing
  259. * the method specified by <code>identifier</code>.
  260. *
  261. * <p>Note that the actual method returned will be have an altered,
  262. * reflective name i.e. <code>_m_2_..</code>.
  263. *
  264. * @param identifier the identifier index
  265. * given to <code>trapMethodcall()</code> etc.
  266. * @see Metaobject#trapMethodcall(int,Object[])
  267. * @see #trapMethodcall(int,Object[])
  268. */
  269. public final Method getMethod(int identifier) {
  270. return getReflectiveMethods()[identifier];
  271. }
  272. /**
  273. * Returns the name of the method specified
  274. * by <code>identifier</code>.
  275. */
  276. public final String getMethodName(int identifier) {
  277. String mname = getReflectiveMethods()[identifier].getName();
  278. int j = ClassMetaobject.methodPrefixLen;
  279. for (;;) {
  280. char c = mname.charAt(j++);
  281. if (c < '0' || '9' < c)
  282. break;
  283. }
  284. return mname.substring(j);
  285. }
  286. /**
  287. * Returns an array of <code>Class</code> objects representing the
  288. * formal parameter types of the method specified
  289. * by <code>identifier</code>.
  290. */
  291. public final Class[] getParameterTypes(int identifier) {
  292. return getReflectiveMethods()[identifier].getParameterTypes();
  293. }
  294. /**
  295. * Returns a <code>Class</code> objects representing the
  296. * return type of the method specified by <code>identifier</code>.
  297. */
  298. public final Class getReturnType(int identifier) {
  299. return getReflectiveMethods()[identifier].getReturnType();
  300. }
  301. /**
  302. * Returns the identifier index of the method, as identified by its
  303. * original name.
  304. *
  305. * <p>This method is useful, in conjuction with
  306. * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
  307. * to the original method in the reflected class (i.e. not the proxy
  308. * method), using the original name of the method.
  309. *
  310. * <p>Written by Brett Randall and Shigeru Chiba.
  311. *
  312. * @param originalName The original name of the reflected method
  313. * @param argTypes array of Class specifying the method signature
  314. * @return the identifier index of the original method
  315. * @throws NoSuchMethodException if the method does not exist
  316. *
  317. * @see ClassMetaobject#getMethod(int)
  318. */
  319. public final int getMethodIndex(String originalName, Class[] argTypes)
  320. throws NoSuchMethodException
  321. {
  322. Method[] mthds = getReflectiveMethods();
  323. for (int i = 0; i < mthds.length; i++) {
  324. if (mthds[i] == null)
  325. continue;
  326. // check name and parameter types match
  327. if (getMethodName(i).equals(originalName)
  328. && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
  329. return i;
  330. }
  331. throw new NoSuchMethodException("Method " + originalName
  332. + " not found");
  333. }
  334. }