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.

MethodInfo.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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.bytecode;
  16. import javassist.bytecode.annotation.AnnotationGroup;
  17. import java.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.Map;
  21. import java.util.List;
  22. import java.util.LinkedList;
  23. /**
  24. * <code>method_info</code> structure.
  25. *
  26. * @see javassist.CtMethod#getMethodInfo()
  27. * @see javassist.CtConstructor#getMethodInfo()
  28. */
  29. public final class MethodInfo {
  30. ConstPool constPool;
  31. int accessFlags;
  32. int name;
  33. int descriptor;
  34. LinkedList attribute; // may be null
  35. AnnotationGroup runtimeInvisible;
  36. AnnotationGroup runtimeVisible;
  37. /**
  38. * The name of constructors: <code>&lt;init&gt</code>.
  39. */
  40. public static final String nameInit = "<init>";
  41. /**
  42. * The name of class initializer (static initializer):
  43. * <code>&lt;clinit&gt</code>.
  44. */
  45. public static final String nameClinit = "<clinit>";
  46. private MethodInfo(ConstPool cp) {
  47. constPool = cp;
  48. attribute = null;
  49. }
  50. /**
  51. * Constructs a <code>method_info</code> structure.
  52. * The initial value of <code>access_flags</code> is zero.
  53. *
  54. * @param cp a constant pool table
  55. * @param methodname method name
  56. * @param desc method descriptor
  57. *
  58. * @see Descriptor
  59. */
  60. public MethodInfo(ConstPool cp, String methodname, String desc) {
  61. this(cp);
  62. accessFlags = 0;
  63. name = cp.addUtf8Info(methodname);
  64. descriptor = constPool.addUtf8Info(desc);
  65. }
  66. MethodInfo(ConstPool cp, DataInputStream in) throws IOException {
  67. this(cp);
  68. read(in);
  69. }
  70. /**
  71. * Constructs a copy of <code>method_info</code> structure.
  72. * Class names appearing in the source <code>method_info</code>
  73. * are renamed according to <code>classnameMap</code>.
  74. *
  75. * <p>Note: only <code>Code</code> and <code>Exceptions</code>
  76. * attributes are copied from the source. The other attributes
  77. * are ignored.
  78. *
  79. * @param cp a constant pool table
  80. * @param methodname a method name
  81. * @param src a source <code>method_info</code>
  82. * @param classnameMap specifies pairs of replaced and substituted
  83. * name.
  84. * @see Descriptor
  85. */
  86. public MethodInfo(ConstPool cp, String methodname, MethodInfo src,
  87. Map classnameMap) throws BadBytecode {
  88. this(cp);
  89. read(src, methodname, classnameMap);
  90. }
  91. /**
  92. * Returns a method name.
  93. */
  94. public String getName() {
  95. return constPool.getUtf8Info(name);
  96. }
  97. /**
  98. * Sets a method name.
  99. */
  100. public void setName(String newName) {
  101. name = constPool.addUtf8Info(newName);
  102. }
  103. /**
  104. * Returns true if this is not a constructor or a class initializer
  105. * (static initializer).
  106. */
  107. public boolean isMethod() {
  108. String n = getName();
  109. return !n.equals(nameInit) && !n.equals(nameClinit);
  110. }
  111. /**
  112. * Returns a constant pool table used by this method.
  113. */
  114. public ConstPool getConstPool() {
  115. return constPool;
  116. }
  117. /**
  118. * Returns true if this is a constructor.
  119. */
  120. public boolean isConstructor() {
  121. return getName().equals(nameInit);
  122. }
  123. /**
  124. * Returns true if this is a class initializer (static initializer).
  125. */
  126. public boolean isStaticInitializer() {
  127. return getName().equals(nameClinit);
  128. }
  129. /**
  130. * Returns access flags.
  131. *
  132. * @see AccessFlag
  133. */
  134. public int getAccessFlags() {
  135. return accessFlags;
  136. }
  137. /**
  138. * Sets access flags.
  139. *
  140. * @see AccessFlag
  141. */
  142. public void setAccessFlags(int acc) {
  143. accessFlags = acc;
  144. }
  145. /**
  146. * Returns a method descriptor.
  147. *
  148. * @see Descriptor
  149. */
  150. public String getDescriptor() {
  151. return constPool.getUtf8Info(descriptor);
  152. }
  153. /**
  154. * Sets a method descriptor.
  155. *
  156. * @see Descriptor
  157. */
  158. public void setDescriptor(String desc) {
  159. if (!desc.equals(getDescriptor()))
  160. descriptor = constPool.addUtf8Info(desc);
  161. }
  162. /**
  163. * Returns all the attributes.
  164. *
  165. * @return a list of <code>AttributeInfo</code> objects.
  166. * @see AttributeInfo
  167. */
  168. public List getAttributes() {
  169. if (attribute == null)
  170. attribute = new LinkedList();
  171. return attribute;
  172. }
  173. /**
  174. * Returns the attribute with the specified name.
  175. * If it is not found, this method returns null.
  176. *
  177. * @param name attribute name
  178. * @return an <code>AttributeInfo</code> object or null.
  179. */
  180. public AttributeInfo getAttribute(String name) {
  181. return AttributeInfo.lookup(attribute, name);
  182. }
  183. /**
  184. * Appends an attribute. If there is already an attribute with
  185. * the same name, the new one substitutes for it.
  186. */
  187. public void addAttribute(AttributeInfo info) {
  188. if (attribute == null)
  189. attribute = new LinkedList();
  190. AttributeInfo.remove(attribute, info.getName());
  191. attribute.add(info);
  192. }
  193. /**
  194. * Create an empty (null) attribute "RuntimeInvisibleAnnotations"
  195. * Usually used so that you can start adding annotations to a particular thing
  196. */
  197. public void createRuntimeInvisibleGroup() {
  198. if (runtimeInvisible == null) {
  199. AttributeInfo attr =
  200. new AttributeInfo(constPool, "RuntimeInvisibleAnnotations");
  201. addAttribute(attr);
  202. runtimeInvisible = new AnnotationGroup(attr);
  203. }
  204. }
  205. /**
  206. * Create an empty (null) attribute "RuntimeVisibleAnnotations"
  207. * Usually used so that you can start adding annotations to a particular thing
  208. */
  209. public void createRuntimeVisibleGroup() {
  210. if (runtimeVisible == null) {
  211. AttributeInfo attr =
  212. new AttributeInfo(constPool, "RuntimeVisibleAnnotations");
  213. addAttribute(attr);
  214. runtimeVisible = new AnnotationGroup(attr);
  215. }
  216. }
  217. /**
  218. * Return access object for getting info about annotations
  219. * This returns runtime invisible annotations as pertains to the
  220. * CLASS RetentionPolicy
  221. * @return
  222. */
  223. public AnnotationGroup getRuntimeInvisibleAnnotations() {
  224. if (runtimeInvisible != null)
  225. return runtimeInvisible;
  226. AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations");
  227. if (invisible == null)
  228. return null;
  229. runtimeInvisible = new AnnotationGroup(invisible);
  230. return runtimeInvisible;
  231. }
  232. /**
  233. * Return access object for getting info about annotations
  234. * This returns runtime visible annotations as pertains to the
  235. * RUNTIME RetentionPolicy
  236. * @return
  237. */
  238. public AnnotationGroup getRuntimeVisibleAnnotations() {
  239. if (runtimeVisible != null)
  240. return runtimeVisible;
  241. AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations");
  242. if (visible == null)
  243. return null;
  244. runtimeVisible = new AnnotationGroup(visible);
  245. return runtimeVisible;
  246. }
  247. /**
  248. * Returns an Exceptions attribute.
  249. *
  250. * @return an Exceptions attribute
  251. * or null if it is not specified.
  252. */
  253. public ExceptionsAttribute getExceptionsAttribute() {
  254. AttributeInfo info
  255. = AttributeInfo.lookup(attribute, ExceptionsAttribute.class);
  256. return (ExceptionsAttribute)info;
  257. }
  258. /**
  259. * Returns a Code attribute.
  260. *
  261. * @return a Code attribute
  262. * or null if it is not specified.
  263. */
  264. public CodeAttribute getCodeAttribute() {
  265. AttributeInfo info
  266. = AttributeInfo.lookup(attribute, CodeAttribute.class);
  267. return (CodeAttribute)info;
  268. }
  269. /**
  270. * Removes an Exception attribute.
  271. */
  272. public void removeExceptionsAttribute() {
  273. AttributeInfo.remove(attribute, ExceptionsAttribute.class);
  274. }
  275. /**
  276. * Adds an Exception attribute.
  277. *
  278. * <p>The added attribute must share the same constant pool table
  279. * as this <code>method_info</code> structure.
  280. */
  281. public void setExceptionsAttribute(ExceptionsAttribute cattr) {
  282. removeExceptionsAttribute();
  283. if (attribute == null)
  284. attribute = new LinkedList();
  285. attribute.add(cattr);
  286. }
  287. /**
  288. * Removes a Code attribute.
  289. */
  290. public void removeCodeAttribute() {
  291. AttributeInfo.remove(attribute, CodeAttribute.class);
  292. }
  293. /**
  294. * Adds a Code attribute.
  295. *
  296. * <p>The added attribute must share the same constant pool table
  297. * as this <code>method_info</code> structure.
  298. */
  299. public void setCodeAttribute(CodeAttribute cattr) {
  300. removeCodeAttribute();
  301. if (attribute == null)
  302. attribute = new LinkedList();
  303. attribute.add(cattr);
  304. }
  305. /**
  306. * Returns the line number of the source line corresponding to the
  307. * specified bytecode contained in this method.
  308. *
  309. * @param pos the position of the bytecode (&gt;= 0).
  310. * an index into the code array.
  311. * @return -1 if this information is not available.
  312. */
  313. public int getLineNumber(int pos) {
  314. CodeAttribute ca = getCodeAttribute();
  315. if (ca == null)
  316. return -1;
  317. LineNumberAttribute ainfo =
  318. (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
  319. if (ainfo == null)
  320. return -1;
  321. return ainfo.toLineNumber(pos);
  322. }
  323. /**
  324. * Changes a super constructor called by this constructor.
  325. *
  326. * <p>This method modifies a call to <code>super()</code>,
  327. * which should be at the
  328. * head of a constructor body, so that a constructor in a different
  329. * super class is called. This method does not change actural
  330. * parameters. Hence the new super class must have a constructor
  331. * with the same signature as the original one.
  332. *
  333. * <p>This method should be called when the super class
  334. * of the class declaring this method is changed.
  335. *
  336. * <p>This method does not perform anything unless this
  337. * <code>MethodInfo</code> represents a constructor.
  338. *
  339. * @param superclass the new super class
  340. */
  341. public void setSuperclass(String superclass) throws BadBytecode {
  342. if (!isConstructor())
  343. return;
  344. CodeAttribute ca = getCodeAttribute();
  345. byte[] code = ca.getCode();
  346. CodeIterator iterator = ca.iterator();
  347. int pos = iterator.skipSuperConstructor();
  348. if (pos >= 0) { // not this()
  349. ConstPool cp = constPool;
  350. int mref = ByteArray.readU16bit(code, pos + 1);
  351. int nt = cp.getMethodrefNameAndType(mref);
  352. int sc = cp.addClassInfo(superclass);
  353. int mref2 = cp.addMethodrefInfo(sc, nt);
  354. ByteArray.write16bit(mref2, code, pos + 1);
  355. }
  356. }
  357. private void read(MethodInfo src, String methodname, Map classnames)
  358. throws BadBytecode
  359. {
  360. ConstPool destCp = constPool;
  361. accessFlags = src.accessFlags;
  362. name = destCp.addUtf8Info(methodname);
  363. ConstPool srcCp = src.constPool;
  364. String desc = srcCp.getUtf8Info(src.descriptor);
  365. String desc2 = Descriptor.rename(desc, classnames);
  366. descriptor = destCp.addUtf8Info(desc2);
  367. attribute = new LinkedList();
  368. ExceptionsAttribute eattr = src.getExceptionsAttribute();
  369. if (eattr != null)
  370. attribute.add(eattr.copy(destCp, classnames));
  371. CodeAttribute cattr = src.getCodeAttribute();
  372. if (cattr != null)
  373. attribute.add(cattr.copy(destCp, classnames));
  374. }
  375. private void read(DataInputStream in) throws IOException {
  376. accessFlags = in.readUnsignedShort();
  377. name = in.readUnsignedShort();
  378. descriptor = in.readUnsignedShort();
  379. int n = in.readUnsignedShort();
  380. attribute = new LinkedList();
  381. for (int i = 0; i < n; ++i)
  382. attribute.add(AttributeInfo.read(constPool, in));
  383. }
  384. void write(DataOutputStream out) throws IOException {
  385. out.writeShort(accessFlags);
  386. out.writeShort(name);
  387. out.writeShort(descriptor);
  388. if (attribute == null)
  389. out.writeShort(0);
  390. else {
  391. out.writeShort(attribute.size());
  392. AttributeInfo.writeAll(attribute, out);
  393. }
  394. }
  395. }