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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 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.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.reflect.Metaobject
  36. * @see javassist.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. methods = new Method[n];
  233. for (int i = 0; i < n; ++i) {
  234. Method m = allmethods[i];
  235. String mname = m.getName();
  236. if (mname.startsWith(methodPrefix)) {
  237. int k = 0;
  238. for (int j = methodPrefixLen;; ++j) {
  239. char c = mname.charAt(j);
  240. if ('0' <= c && c <= '9')
  241. k = k * 10 + c - '0';
  242. else
  243. break;
  244. }
  245. methods[k] = m;
  246. }
  247. }
  248. return methods;
  249. }
  250. /**
  251. * Returns the <code>java.lang.reflect.Method</code> object representing
  252. * the method specified by <code>identifier</code>.
  253. *
  254. * <p>Note that the actual method returned will be have an altered,
  255. * reflective name i.e. <code>_m_2_..</code>.
  256. *
  257. * @param identifier the identifier index
  258. * given to <code>trapMethodcall()</code> etc.
  259. * @see Metaobject#trapMethodcall(int,Object[])
  260. * @see #trapMethodcall(int,Object[])
  261. */
  262. public final Method getMethod(int identifier) {
  263. return getReflectiveMethods()[identifier];
  264. }
  265. /**
  266. * Returns the name of the method specified
  267. * by <code>identifier</code>.
  268. */
  269. public final String getMethodName(int identifier) {
  270. String mname = getReflectiveMethods()[identifier].getName();
  271. int j = ClassMetaobject.methodPrefixLen;
  272. for (;;) {
  273. char c = mname.charAt(j++);
  274. if (c < '0' || '9' < c)
  275. break;
  276. }
  277. return mname.substring(j);
  278. }
  279. /**
  280. * Returns an array of <code>Class</code> objects representing the
  281. * formal parameter types of the method specified
  282. * by <code>identifier</code>.
  283. */
  284. public final Class[] getParameterTypes(int identifier) {
  285. return getReflectiveMethods()[identifier].getParameterTypes();
  286. }
  287. /**
  288. * Returns a <code>Class</code> objects representing the
  289. * return type of the method specified by <code>identifier</code>.
  290. */
  291. public final Class getReturnType(int identifier) {
  292. return getReflectiveMethods()[identifier].getReturnType();
  293. }
  294. /**
  295. * Returns the identifier index of the method, as identified by its
  296. * original name.
  297. *
  298. * <p>This method is useful, in conjuction with
  299. * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
  300. * to the original method in the reflected class (i.e. not the proxy
  301. * method), using the original name of the method.
  302. *
  303. * <p>Written by Brett Randall and Shigeru Chiba.
  304. *
  305. * @param originalName The original name of the reflected method
  306. * @param argTypes array of Class specifying the method signature
  307. * @return the identifier index of the original method
  308. * @throws NoSuchMethodException if the method does not exist
  309. *
  310. * @see ClassMetaobject#getMethod(int)
  311. */
  312. public final int getMethodIndex(String originalName, Class[] argTypes)
  313. throws NoSuchMethodException
  314. {
  315. Method[] mthds = getReflectiveMethods();
  316. for (int i = 0; i < mthds.length; i++) {
  317. if (mthds[i] == null)
  318. continue;
  319. // check name and parameter types match
  320. if (getMethodName(i).equals(originalName)
  321. && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
  322. return i;
  323. }
  324. throw new NoSuchMethodException("Method " + originalName
  325. + " not found");
  326. }
  327. }