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.

CtMethod.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 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;
  16. import javassist.bytecode.*;
  17. import javassist.expr.ExprEditor;
  18. /* Some methods do nothing except calling the super's method.
  19. * They might seem redundant but they are necessary so that javadoc
  20. * includes the description of those methods in the page of this class.
  21. */
  22. /**
  23. * An instance of <code>CtMethod</code> represents a method.
  24. *
  25. * @see CtClass#getDeclaredMethods()
  26. * @see CtNewMethod
  27. */
  28. public final class CtMethod extends CtBehavior {
  29. protected CtMethod next;
  30. protected int cachedHashCode;
  31. CtMethod(MethodInfo minfo, CtClass declaring) {
  32. super(declaring, minfo);
  33. next = null;
  34. cachedHashCode = 0;
  35. }
  36. /**
  37. * Creates a public abstract method. The created method must be
  38. * added to a class with <code>CtClass.addMethod()</code>.
  39. *
  40. * @param declaring the class to which the created method is added.
  41. * @param returnType the type of the returned value
  42. * @param mname the method name
  43. * @param parameters a list of the parameter types
  44. *
  45. * @see CtClass#addMethod(CtMethod)
  46. */
  47. public CtMethod(CtClass returnType, String mname,
  48. CtClass[] parameters, CtClass declaring) {
  49. this(null, declaring);
  50. ConstPool cp = declaring.getClassFile2().getConstPool();
  51. String desc = Descriptor.ofMethod(returnType, parameters);
  52. methodInfo = new MethodInfo(cp, mname, desc);
  53. setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
  54. }
  55. /**
  56. * Creates a copy of a <code>CtMethod</code> object.
  57. * The created method must be
  58. * added to a class with <code>CtClass.addMethod()</code>.
  59. *
  60. * <p>All occurrences of class names in the created method
  61. * are replaced with names specified by
  62. * <code>map</code> if <code>map</code> is not <code>null</code>.
  63. *
  64. * <p>For example, suppose that a method <code>at()</code> is as
  65. * follows:
  66. *
  67. * <ul><pre>public X at(int i) {
  68. * return (X)super.elementAt(i);
  69. * }</pre></ul>
  70. *
  71. * <p>(<code>X</code> is a class name.) If <code>map</code> substitutes
  72. * <code>String</code> for <code>X</code>, then the created method is:
  73. *
  74. * <ul><pre>public String at(int i) {
  75. * return (String)super.elementAt(i);
  76. * }</pre></ul>
  77. *
  78. * <p>By default, all the occurrences of the names of the class
  79. * declaring <code>at()</code> and the superclass are replaced
  80. * with the name of the class and the superclass that the
  81. * created method is added to.
  82. * This is done whichever <code>map</code> is null or not.
  83. * To prevent this replacement, call <code>ClassMap.fix()</code>.
  84. *
  85. * <p><b>Note:</b> if the <code>.class</code> notation (for example,
  86. * <code>String.class</code>) is included in an expression, the
  87. * Javac compiler may produce a helper method.
  88. * Since this constructor never
  89. * copies this helper method, the programmers have the responsiblity of
  90. * copying it. Otherwise, use <code>Class.forName()</code> in the
  91. * expression.
  92. *
  93. * @param src the source method.
  94. * @param declaring the class to which the created method is added.
  95. * @param map the hashtable associating original class names
  96. * with substituted names.
  97. * It can be <code>null</code>.
  98. *
  99. * @see CtClass#addMethod(CtMethod)
  100. * @see ClassMap#fix(String)
  101. */
  102. public CtMethod(CtMethod src, CtClass declaring, ClassMap map)
  103. throws CannotCompileException
  104. {
  105. this(null, declaring);
  106. MethodInfo srcInfo = src.methodInfo;
  107. CtClass srcClass = src.getDeclaringClass();
  108. ConstPool cp = declaring.getClassFile2().getConstPool();
  109. if (map == null)
  110. map = new ClassMap();
  111. map.put(srcClass.getName(), declaring.getName());
  112. try {
  113. CtClass srcSuper = srcClass.getSuperclass();
  114. if (srcSuper != null) {
  115. String srcSuperName = srcSuper.getName();
  116. if (!srcSuperName.equals(CtClass.javaLangObject))
  117. map.put(srcSuperName,
  118. declaring.getSuperclass().getName());
  119. }
  120. methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map);
  121. }
  122. catch (NotFoundException e) {
  123. throw new CannotCompileException(e);
  124. }
  125. catch (BadBytecode e) {
  126. throw new CannotCompileException(e);
  127. }
  128. }
  129. static CtMethod append(CtMethod list, CtMethod tail) {
  130. tail.next = null;
  131. if (list == null)
  132. return tail;
  133. else {
  134. CtMethod lst = list;
  135. while (lst.next != null)
  136. lst = lst.next;
  137. lst.next = tail;
  138. return list;
  139. }
  140. }
  141. static int count(CtMethod m) {
  142. int n = 0;
  143. while (m != null) {
  144. ++n;
  145. m = m.next;
  146. }
  147. return n;
  148. }
  149. /**
  150. * Returns a hash code value for the method.
  151. * If two methods have the same name and signature, then
  152. * the hash codes for the two methods are equal.
  153. */
  154. public int hashCode() {
  155. /* This method is overridden in ExistingMethod for optimization.
  156. */
  157. if (cachedHashCode == 0) {
  158. String signature
  159. = methodInfo.getName() + ':' + methodInfo.getDescriptor();
  160. // System.identityHashCode() returns 0 only for null.
  161. cachedHashCode = System.identityHashCode(signature.intern());
  162. }
  163. return cachedHashCode;
  164. }
  165. /**
  166. * Indicates whether <code>obj</code> has the same name and the
  167. * same signature as this method.
  168. */
  169. public boolean equals(Object obj) {
  170. return obj != null && obj instanceof CtMethod
  171. && obj.hashCode() == hashCode();
  172. }
  173. /**
  174. * Returns the MethodInfo representing the method in the class file.
  175. */
  176. public MethodInfo getMethodInfo() {
  177. return super.getMethodInfo();
  178. }
  179. /**
  180. * Obtains the modifiers of the method.
  181. *
  182. * @return modifiers encoded with
  183. * <code>javassist.Modifier</code>.
  184. * @see Modifier
  185. */
  186. public int getModifiers() {
  187. return super.getModifiers();
  188. }
  189. /**
  190. * Sets the encoded modifiers of the method.
  191. *
  192. * <p>Changing the modifiers may cause a problem.
  193. * For example, if a non-static method is changed to static,
  194. * the method will be rejected by the bytecode verifier.
  195. *
  196. * @see Modifier
  197. */
  198. public void setModifiers(int mod) {
  199. super.setModifiers(mod);
  200. }
  201. /**
  202. * Obtains the name of this method.
  203. */
  204. public String getName() {
  205. return methodInfo.getName();
  206. }
  207. /**
  208. * Changes the name of this method.
  209. */
  210. public void setName(String newname) {
  211. declaringClass.checkModify();
  212. methodInfo.setName(newname);
  213. }
  214. /**
  215. * Returns the class that declares this method.
  216. */
  217. public CtClass getDeclaringClass() {
  218. return super.getDeclaringClass();
  219. }
  220. /**
  221. * Obtains parameter types of this method.
  222. */
  223. public CtClass[] getParameterTypes() throws NotFoundException {
  224. return super.getParameterTypes();
  225. }
  226. /**
  227. * Obtains the type of the returned value.
  228. */
  229. public CtClass getReturnType() throws NotFoundException {
  230. return getReturnType0();
  231. }
  232. /**
  233. * Returns the character string representing the parameter types
  234. * and the return type. If two methods have the same parameter types
  235. * and the return type, <code>getSignature()</code> returns the
  236. * same string.
  237. */
  238. public String getSignature() {
  239. return super.getSignature();
  240. }
  241. /**
  242. * Obtains exceptions that this method may throw.
  243. */
  244. public CtClass[] getExceptionTypes() throws NotFoundException {
  245. return super.getExceptionTypes();
  246. }
  247. /**
  248. * Sets exceptions that this method may throw.
  249. *
  250. * @param types exception types (or null)
  251. */
  252. public void setExceptionTypes(CtClass[] types) throws NotFoundException {
  253. super.setExceptionTypes(types);
  254. }
  255. /**
  256. * Returns true if the method body is empty, that is, <code>{}</code>.
  257. * It also returns true if the method is an abstract method.
  258. */
  259. public boolean isEmpty() {
  260. CodeAttribute ca = getMethodInfo2().getCodeAttribute();
  261. if (ca == null) // abstract or native
  262. return (getModifiers() & Modifier.ABSTRACT) != 0;
  263. CodeIterator it = ca.iterator();
  264. try {
  265. return it.hasNext() && it.byteAt(it.next()) == Opcode.RETURN
  266. && !it.hasNext();
  267. }
  268. catch (BadBytecode e) {}
  269. return false;
  270. }
  271. /**
  272. * Sets a method body.
  273. *
  274. * @param src the source code representing the method body.
  275. * It must be a single statement or block.
  276. */
  277. public void setBody(String src) throws CannotCompileException {
  278. super.setBody(src);
  279. }
  280. /**
  281. * Copies a method body from another method.
  282. * If this method is abstract, the abstract modifier is removed
  283. * after the method body is copied.
  284. *
  285. * <p>All occurrences of the class names in the copied method body
  286. * are replaced with the names specified by
  287. * <code>map</code> if <code>map</code> is not <code>null</code>.
  288. *
  289. * @param src the method that the body is copied from.
  290. * @param map the hashtable associating original class names
  291. * with substituted names.
  292. * It can be <code>null</code>.
  293. */
  294. public void setBody(CtMethod src, ClassMap map)
  295. throws CannotCompileException
  296. {
  297. setBody0(src.declaringClass, src.methodInfo,
  298. declaringClass, methodInfo, map);
  299. }
  300. /**
  301. * Replace a method body with a new method body wrapping the
  302. * given method.
  303. *
  304. * @param mbody the wrapped method
  305. * @param constParam the constant parameter given to
  306. * the wrapped method
  307. * (maybe <code>null</code>).
  308. *
  309. * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
  310. */
  311. public void setWrappedBody(CtMethod mbody, ConstParameter constParam)
  312. throws CannotCompileException
  313. {
  314. declaringClass.checkModify();
  315. CtClass clazz = getDeclaringClass();
  316. CtClass[] params;
  317. CtClass retType;
  318. try {
  319. params = getParameterTypes();
  320. retType = getReturnType();
  321. }
  322. catch (NotFoundException e) {
  323. throw new CannotCompileException(e);
  324. }
  325. Bytecode code = CtNewWrappedMethod.makeBody(clazz,
  326. clazz.getClassFile2(),
  327. mbody,
  328. params, retType,
  329. constParam);
  330. CodeAttribute cattr = code.toCodeAttribute();
  331. methodInfo.setCodeAttribute(cattr);
  332. methodInfo.setAccessFlags(methodInfo.getAccessFlags()
  333. & ~AccessFlag.ABSTRACT);
  334. }
  335. /**
  336. * Obtains an attribute with the given name.
  337. * If that attribute is not found in the class file, this
  338. * method returns null.
  339. *
  340. * @param name attribute name
  341. */
  342. public byte[] getAttribute(String name) {
  343. return super.getAttribute(name);
  344. }
  345. /**
  346. * Adds an attribute. The attribute is saved in the class file.
  347. *
  348. * @param name attribute name
  349. * @param data attribute value
  350. */
  351. public void setAttribute(String name, byte[] data) {
  352. super.setAttribute(name, data);
  353. }
  354. /**
  355. * Declares to use <code>$cflow</code> for this method.
  356. * If <code>$cflow</code> is used, the class files modified
  357. * with Javassist requires a support class
  358. * <code>javassist.runtime.Cflow</code> at runtime
  359. * (other Javassist classes are not required at runtime).
  360. *
  361. * <p>Every <code>$cflow</code> variable is given a unique name.
  362. * For example, if the given name is <code>"Point.paint"</code>,
  363. * then the variable is indicated by <code>$cflow(Point.paint)</code>.
  364. *
  365. * @param name <code>$cflow</code> name. It can include
  366. * alphabets, numbers, <code>_</code>,
  367. * <code>$</code>, and <code>.</code> (dot).
  368. *
  369. * @see javassist.runtime.Cflow
  370. */
  371. public void useCflow(String name) throws CannotCompileException {
  372. super.useCflow(name);
  373. }
  374. /**
  375. * Modifies the method body.
  376. *
  377. * @param converter specifies how to modify.
  378. */
  379. public void instrument(CodeConverter converter)
  380. throws CannotCompileException
  381. {
  382. super.instrument(converter);
  383. }
  384. /**
  385. * Modifies the method body.
  386. *
  387. * @param editor specifies how to modify.
  388. */
  389. public void instrument(ExprEditor editor)
  390. throws CannotCompileException
  391. {
  392. super.instrument(editor);
  393. }
  394. /**
  395. * Inserts bytecode at the beginning of the method body.
  396. *
  397. * @param src the source code representing the inserted bytecode.
  398. * It must be a single statement or block.
  399. */
  400. public void insertBefore(String src) throws CannotCompileException {
  401. super.insertBefore(src);
  402. }
  403. /**
  404. * Inserts bytecode at the end of the method body.
  405. * The bytecode is inserted just before every return insturction.
  406. * It is not executed when an exception is thrown.
  407. *
  408. * @param src the source code representing the inserted bytecode.
  409. * It must be a single statement or block.
  410. */
  411. public void insertAfter(String src)
  412. throws CannotCompileException
  413. {
  414. super.insertAfter(src);
  415. }
  416. /**
  417. * Inserts bytecode at the end of the method body.
  418. * The bytecode is inserted just before every return insturction.
  419. *
  420. * @param src the source code representing the inserted bytecode.
  421. * It must be a single statement or block.
  422. * @param asFinally true if the inserted bytecode is executed
  423. * not only when the transfer normally returns
  424. * but also when an exception is thrown.
  425. */
  426. public void insertAfter(String src, boolean asFinally)
  427. throws CannotCompileException
  428. {
  429. super.insertAfter(src, asFinally);
  430. }
  431. /**
  432. * Adds a catch clause that handles an exception thrown in the
  433. * method body.
  434. * The catch clause must end with a return or throw statement.
  435. *
  436. * @param src the source code representing the catch clause.
  437. * It must be a single statement or block.
  438. * @param exceptionType the type of the exception handled by the
  439. * catch clause.
  440. */
  441. public void addCatch(String src, CtClass exceptionType)
  442. throws CannotCompileException
  443. {
  444. super.addCatch(src, exceptionType);
  445. }
  446. // inner classes
  447. /**
  448. * Instances of this class represent a constant parameter.
  449. * They are used to specify the parameter given to the methods
  450. * created by <code>CtNewMethod.wrapped()</code>.
  451. *
  452. * @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter)
  453. * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
  454. * @see CtNewConstructor#make(CtClass[],CtClass[],int,CtMethod,CtMethod.ConstParameter,CtClass)
  455. */
  456. public static class ConstParameter {
  457. /**
  458. * Makes an integer constant.
  459. *
  460. * @param i the constant value.
  461. */
  462. public static ConstParameter integer(int i) {
  463. return new IntConstParameter(i);
  464. }
  465. /**
  466. * Makes a long integer constant.
  467. *
  468. * @param i the constant value.
  469. */
  470. public static ConstParameter integer(long i) {
  471. return new LongConstParameter(i);
  472. }
  473. /**
  474. * Makes an <code>String</code> constant.
  475. *
  476. * @param s the constant value.
  477. */
  478. public static ConstParameter string(String s) {
  479. return new StringConstParameter(s);
  480. }
  481. ConstParameter() {}
  482. /**
  483. * @return the size of the stack consumption.
  484. */
  485. int compile(Bytecode code) throws CannotCompileException {
  486. return 0;
  487. }
  488. String descriptor() {
  489. return defaultDescriptor();
  490. }
  491. /**
  492. * @see CtNewWrappedMethod
  493. */
  494. static String defaultDescriptor() {
  495. return "([Ljava/lang/Object;)Ljava/lang/Object;";
  496. }
  497. /**
  498. * Returns the descriptor for constructors.
  499. *
  500. * @see CtNewWrappedConstructor
  501. */
  502. String constDescriptor() {
  503. return defaultConstDescriptor();
  504. }
  505. /**
  506. * Returns the default descriptor for constructors.
  507. */
  508. static String defaultConstDescriptor() {
  509. return "([Ljava/lang/Object;)V";
  510. }
  511. }
  512. static class IntConstParameter extends ConstParameter {
  513. int param;
  514. IntConstParameter(int i) {
  515. param = i;
  516. }
  517. int compile(Bytecode code) throws CannotCompileException {
  518. code.addIconst(param);
  519. return 1;
  520. }
  521. String descriptor() {
  522. return "([Ljava/lang/Object;I)Ljava/lang/Object;";
  523. }
  524. String constDescriptor() {
  525. return "([Ljava/lang/Object;I)V";
  526. }
  527. }
  528. static class LongConstParameter extends ConstParameter {
  529. long param;
  530. LongConstParameter(long l) {
  531. param = l;
  532. }
  533. int compile(Bytecode code) throws CannotCompileException {
  534. code.addLconst(param);
  535. return 2;
  536. }
  537. String descriptor() {
  538. return "([Ljava/lang/Object;J)Ljava/lang/Object;";
  539. }
  540. String constDescriptor() {
  541. return "([Ljava/lang/Object;J)V";
  542. }
  543. }
  544. static class StringConstParameter extends ConstParameter {
  545. String param;
  546. StringConstParameter(String s) {
  547. param = s;
  548. }
  549. int compile(Bytecode code) throws CannotCompileException {
  550. code.addLdc(param);
  551. return 1;
  552. }
  553. String descriptor() {
  554. return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
  555. }
  556. String constDescriptor() {
  557. return "([Ljava/lang/Object;Ljava/lang/String;)V";
  558. }
  559. }
  560. }