您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ClassFile.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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.bytecode;
  17. import java.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.Collection;
  22. import java.util.List;
  23. import java.util.ListIterator;
  24. import java.util.Map;
  25. import javassist.CannotCompileException;
  26. /**
  27. * <code>ClassFile</code> represents a Java <code>.class</code> file, which
  28. * consists of a constant pool, methods, fields, and attributes.
  29. *
  30. * <p>For example,</p>
  31. * <blockquote><pre>
  32. * ClassFile cf = new ClassFile(false, "test.Foo", null);
  33. * cf.setInterfaces(new String[] { "java.lang.Cloneable" });
  34. *
  35. * FieldInfo f = new FieldInfo(cf.getConstPool(), "width", "I");
  36. * f.setAccessFlags(AccessFlag.PUBLIC);
  37. * cf.addField(f);
  38. *
  39. * cf.write(new DataOutputStream(new FileOutputStream("Foo.class")));
  40. * </pre></blockquote>
  41. * <p>This code generates a class file <code>Foo.class</code> for the following class:</p>
  42. * <blockquote><pre>
  43. * package test;
  44. * class Foo implements Cloneable {
  45. * public int width;
  46. * }
  47. * </pre></blockquote>
  48. *
  49. * @see FieldInfo
  50. * @see MethodInfo
  51. * @see ClassFileWriter
  52. * @see javassist.CtClass#getClassFile()
  53. * @see javassist.ClassPool#makeClass(ClassFile)
  54. */
  55. public final class ClassFile {
  56. int major, minor; // version number
  57. ConstPool constPool;
  58. int thisClass;
  59. int accessFlags;
  60. int superClass;
  61. int[] interfaces;
  62. List<FieldInfo> fields;
  63. List<MethodInfo> methods;
  64. List<AttributeInfo> attributes;
  65. String thisclassname; // not JVM-internal name
  66. String[] cachedInterfaces;
  67. String cachedSuperclass;
  68. /**
  69. * The major version number of class files
  70. * for JDK 1.1.
  71. */
  72. public static final int JAVA_1 = 45;
  73. /**
  74. * The major version number of class files
  75. * for JDK 1.2.
  76. */
  77. public static final int JAVA_2 = 46;
  78. /**
  79. * The major version number of class files
  80. * for JDK 1.3.
  81. */
  82. public static final int JAVA_3 = 47;
  83. /**
  84. * The major version number of class files
  85. * for JDK 1.4.
  86. */
  87. public static final int JAVA_4 = 48;
  88. /**
  89. * The major version number of class files
  90. * for JDK 1.5.
  91. */
  92. public static final int JAVA_5 = 49;
  93. /**
  94. * The major version number of class files
  95. * for JDK 1.6.
  96. */
  97. public static final int JAVA_6 = 50;
  98. /**
  99. * The major version number of class files
  100. * for JDK 1.7.
  101. */
  102. public static final int JAVA_7 = 51;
  103. /**
  104. * The major version number of class files
  105. * for JDK 1.8.
  106. */
  107. public static final int JAVA_8 = 52;
  108. /**
  109. * The major version number of class files
  110. * for JDK 1.9.
  111. */
  112. public static final int JAVA_9 = 53;
  113. /**
  114. * The major version number of class files
  115. * for JDK 10.
  116. */
  117. public static final int JAVA_10 = 54;
  118. /**
  119. * The major version number of class files
  120. * for JDK 11.
  121. */
  122. public static final int JAVA_11 = 55;
  123. /**
  124. * The major version number of class files created
  125. * from scratch. The default value is 47 (JDK 1.3).
  126. * It is 49 (JDK 1.5)
  127. * if the JVM supports <code>java.lang.StringBuilder</code>.
  128. * It is 50 (JDK 1.6)
  129. * if the JVM supports <code>java.util.zip.DeflaterInputStream</code>.
  130. * It is 51 (JDK 1.7)
  131. * if the JVM supports <code>java.lang.invoke.CallSite</code>.
  132. * It is 52 (JDK 1.8)
  133. * if the JVM supports <code>java.util.function.Function</code>.
  134. * It is 53 (JDK 1.9)
  135. * if the JVM supports <code>java.lang.reflect.Module</code>.
  136. * It is 54 (JDK 10)
  137. * if the JVM supports <code>java.util.List.copyOf(Collection)</code>.
  138. * It is 55 (JDK 11)
  139. * if the JVM supports <code>java.util.Optional.isEmpty()</code>.
  140. */
  141. public static final int MAJOR_VERSION;
  142. static {
  143. int ver = JAVA_3;
  144. try {
  145. Class.forName("java.lang.StringBuilder");
  146. ver = JAVA_5;
  147. Class.forName("java.util.zip.DeflaterInputStream");
  148. ver = JAVA_6;
  149. Class.forName("java.lang.invoke.CallSite", false, ClassLoader.getSystemClassLoader());
  150. ver = JAVA_7;
  151. Class.forName("java.util.function.Function");
  152. ver = JAVA_8;
  153. Class.forName("java.lang.Module");
  154. ver = JAVA_9;
  155. List.class.getMethod("copyOf", Collection.class);
  156. ver = JAVA_10;
  157. Class.forName("java.util.Optional").getMethod("isEmpty");
  158. ver = JAVA_11;
  159. }
  160. catch (Throwable t) {}
  161. MAJOR_VERSION = ver;
  162. }
  163. /**
  164. * Constructs a class file from a byte stream.
  165. */
  166. public ClassFile(DataInputStream in) throws IOException {
  167. read(in);
  168. }
  169. /**
  170. * Constructs a class file including no members.
  171. *
  172. * @param isInterface
  173. * true if this is an interface. false if this is a class.
  174. * @param classname
  175. * a fully-qualified class name
  176. * @param superclass
  177. * a fully-qualified super class name or null.
  178. */
  179. public ClassFile(boolean isInterface, String classname, String superclass) {
  180. major = MAJOR_VERSION;
  181. minor = 0; // JDK 1.3 or later
  182. constPool = new ConstPool(classname);
  183. thisClass = constPool.getThisClassInfo();
  184. if (isInterface)
  185. accessFlags = AccessFlag.INTERFACE | AccessFlag.ABSTRACT;
  186. else
  187. accessFlags = AccessFlag.SUPER;
  188. initSuperclass(superclass);
  189. interfaces = null;
  190. fields = new ArrayList<FieldInfo>();
  191. methods = new ArrayList<MethodInfo>();
  192. thisclassname = classname;
  193. attributes = new ArrayList<AttributeInfo>();
  194. attributes.add(new SourceFileAttribute(constPool,
  195. getSourcefileName(thisclassname)));
  196. }
  197. private void initSuperclass(String superclass) {
  198. if (superclass != null) {
  199. this.superClass = constPool.addClassInfo(superclass);
  200. cachedSuperclass = superclass;
  201. }
  202. else {
  203. this.superClass = constPool.addClassInfo("java.lang.Object");
  204. cachedSuperclass = "java.lang.Object";
  205. }
  206. }
  207. private static String getSourcefileName(String qname) {
  208. return qname.replaceAll("^.*\\.","") + ".java";
  209. }
  210. /**
  211. * Eliminates dead constant pool items. If a method or a field is removed,
  212. * the constant pool items used by that method/field become dead items. This
  213. * method recreates a constant pool.
  214. */
  215. public void compact() {
  216. ConstPool cp = compact0();
  217. for (MethodInfo minfo:methods)
  218. minfo.compact(cp);
  219. for (FieldInfo finfo:fields)
  220. finfo.compact(cp);
  221. attributes = AttributeInfo.copyAll(attributes, cp);
  222. constPool = cp;
  223. }
  224. private ConstPool compact0() {
  225. ConstPool cp = new ConstPool(thisclassname);
  226. thisClass = cp.getThisClassInfo();
  227. String sc = getSuperclass();
  228. if (sc != null)
  229. superClass = cp.addClassInfo(getSuperclass());
  230. if (interfaces != null)
  231. for (int i = 0; i < interfaces.length; ++i)
  232. interfaces[i]
  233. = cp.addClassInfo(constPool.getClassInfo(interfaces[i]));
  234. return cp;
  235. }
  236. /**
  237. * Discards all attributes, associated with both the class file and the
  238. * members such as a code attribute and exceptions attribute. The unused
  239. * constant pool entries are also discarded (a new packed constant pool is
  240. * constructed).
  241. */
  242. public void prune() {
  243. ConstPool cp = compact0();
  244. List<AttributeInfo> newAttributes = new ArrayList<AttributeInfo>();
  245. AttributeInfo invisibleAnnotations
  246. = getAttribute(AnnotationsAttribute.invisibleTag);
  247. if (invisibleAnnotations != null) {
  248. invisibleAnnotations = invisibleAnnotations.copy(cp, null);
  249. newAttributes.add(invisibleAnnotations);
  250. }
  251. AttributeInfo visibleAnnotations
  252. = getAttribute(AnnotationsAttribute.visibleTag);
  253. if (visibleAnnotations != null) {
  254. visibleAnnotations = visibleAnnotations.copy(cp, null);
  255. newAttributes.add(visibleAnnotations);
  256. }
  257. AttributeInfo signature
  258. = getAttribute(SignatureAttribute.tag);
  259. if (signature != null) {
  260. signature = signature.copy(cp, null);
  261. newAttributes.add(signature);
  262. }
  263. for (MethodInfo minfo:methods)
  264. minfo.prune(cp);
  265. for (FieldInfo finfo:fields)
  266. finfo.prune(cp);
  267. attributes = newAttributes;
  268. constPool = cp;
  269. }
  270. /**
  271. * Returns a constant pool table.
  272. */
  273. public ConstPool getConstPool() {
  274. return constPool;
  275. }
  276. /**
  277. * Returns true if this is an interface.
  278. */
  279. public boolean isInterface() {
  280. return (accessFlags & AccessFlag.INTERFACE) != 0;
  281. }
  282. /**
  283. * Returns true if this is a final class or interface.
  284. */
  285. public boolean isFinal() {
  286. return (accessFlags & AccessFlag.FINAL) != 0;
  287. }
  288. /**
  289. * Returns true if this is an abstract class or an interface.
  290. */
  291. public boolean isAbstract() {
  292. return (accessFlags & AccessFlag.ABSTRACT) != 0;
  293. }
  294. /**
  295. * Returns access flags.
  296. *
  297. * @see javassist.bytecode.AccessFlag
  298. */
  299. public int getAccessFlags() {
  300. return accessFlags;
  301. }
  302. /**
  303. * Changes access flags.
  304. *
  305. * @see javassist.bytecode.AccessFlag
  306. */
  307. public void setAccessFlags(int acc) {
  308. if ((acc & AccessFlag.INTERFACE) == 0)
  309. acc |= AccessFlag.SUPER;
  310. accessFlags = acc;
  311. }
  312. /**
  313. * Returns access and property flags of this nested class.
  314. * This method returns -1 if the class is not a nested class.
  315. *
  316. * <p>The returned value is obtained from <code>inner_class_access_flags</code>
  317. * of the entry representing this nested class itself
  318. * in <code>InnerClasses_attribute</code>.
  319. */
  320. public int getInnerAccessFlags() {
  321. InnerClassesAttribute ica
  322. = (InnerClassesAttribute)getAttribute(InnerClassesAttribute.tag);
  323. if (ica == null)
  324. return -1;
  325. String name = getName();
  326. int n = ica.tableLength();
  327. for (int i = 0; i < n; ++i)
  328. if (name.equals(ica.innerClass(i)))
  329. return ica.accessFlags(i);
  330. return -1;
  331. }
  332. /**
  333. * Returns the class name.
  334. */
  335. public String getName() {
  336. return thisclassname;
  337. }
  338. /**
  339. * Sets the class name. This method substitutes the new name for all
  340. * occurrences of the old class name in the class file.
  341. */
  342. public void setName(String name) {
  343. renameClass(thisclassname, name);
  344. }
  345. /**
  346. * Returns the super class name.
  347. */
  348. public String getSuperclass() {
  349. if (cachedSuperclass == null)
  350. cachedSuperclass = constPool.getClassInfo(superClass);
  351. return cachedSuperclass;
  352. }
  353. /**
  354. * Returns the index of the constant pool entry representing the super
  355. * class.
  356. */
  357. public int getSuperclassId() {
  358. return superClass;
  359. }
  360. /**
  361. * Sets the super class.
  362. *
  363. * <p>
  364. * The new super class should inherit from the old super class.
  365. * This method modifies constructors so that they call constructors declared
  366. * in the new super class.
  367. */
  368. public void setSuperclass(String superclass) throws CannotCompileException {
  369. if (superclass == null)
  370. superclass = "java.lang.Object";
  371. try {
  372. this.superClass = constPool.addClassInfo(superclass);
  373. for (MethodInfo minfo:methods)
  374. minfo.setSuperclass(superclass);
  375. }
  376. catch (BadBytecode e) {
  377. throw new CannotCompileException(e);
  378. }
  379. cachedSuperclass = superclass;
  380. }
  381. /**
  382. * Replaces all occurrences of a class name in the class file.
  383. *
  384. * <p>
  385. * If class X is substituted for class Y in the class file, X and Y must
  386. * have the same signature. If Y provides a method m(), X must provide it
  387. * even if X inherits m() from the super class. If this fact is not
  388. * guaranteed, the bytecode verifier may cause an error.
  389. *
  390. * @param oldname
  391. * the replaced class name
  392. * @param newname
  393. * the substituted class name
  394. */
  395. public final void renameClass(String oldname, String newname) {
  396. if (oldname.equals(newname))
  397. return;
  398. if (oldname.equals(thisclassname))
  399. thisclassname = newname;
  400. oldname = Descriptor.toJvmName(oldname);
  401. newname = Descriptor.toJvmName(newname);
  402. constPool.renameClass(oldname, newname);
  403. AttributeInfo.renameClass(attributes, oldname, newname);
  404. for (MethodInfo minfo :methods) {
  405. String desc = minfo.getDescriptor();
  406. minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
  407. AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname);
  408. }
  409. for (FieldInfo finfo:fields) {
  410. String desc = finfo.getDescriptor();
  411. finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
  412. AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname);
  413. }
  414. }
  415. /**
  416. * Replaces all occurrences of several class names in the class file.
  417. *
  418. * @param classnames
  419. * specifies which class name is replaced with which new name.
  420. * Class names must be described with the JVM-internal
  421. * representation like <code>java/lang/Object</code>.
  422. * @see #renameClass(String,String)
  423. */
  424. public final void renameClass(Map<String,String> classnames) {
  425. String jvmNewThisName = classnames.get(Descriptor
  426. .toJvmName(thisclassname));
  427. if (jvmNewThisName != null)
  428. thisclassname = Descriptor.toJavaName(jvmNewThisName);
  429. constPool.renameClass(classnames);
  430. AttributeInfo.renameClass(attributes, classnames);
  431. for (MethodInfo minfo:methods) {
  432. String desc = minfo.getDescriptor();
  433. minfo.setDescriptor(Descriptor.rename(desc, classnames));
  434. AttributeInfo.renameClass(minfo.getAttributes(), classnames);
  435. }
  436. for (FieldInfo finfo:fields) {
  437. String desc = finfo.getDescriptor();
  438. finfo.setDescriptor(Descriptor.rename(desc, classnames));
  439. AttributeInfo.renameClass(finfo.getAttributes(), classnames);
  440. }
  441. }
  442. /**
  443. * Internal-use only.
  444. * <code>CtClass.getRefClasses()</code> calls this method.
  445. */
  446. public final void getRefClasses(Map<String,String> classnames) {
  447. constPool.renameClass(classnames);
  448. AttributeInfo.getRefClasses(attributes, classnames);
  449. for (MethodInfo minfo:methods) {
  450. String desc = minfo.getDescriptor();
  451. Descriptor.rename(desc, classnames);
  452. AttributeInfo.getRefClasses(minfo.getAttributes(), classnames);
  453. }
  454. for (FieldInfo finfo:fields) {
  455. String desc = finfo.getDescriptor();
  456. Descriptor.rename(desc, classnames);
  457. AttributeInfo.getRefClasses(finfo.getAttributes(), classnames);
  458. }
  459. }
  460. /**
  461. * Internal-use only.
  462. * <code>CtClass.getAllRefClasses()</code> calls this method.
  463. */
  464. public final void getAllRefClasses(Map<String, String> classnames) {
  465. constPool.renameClass(classnames);
  466. AttributeInfo.getRefClasses(attributes, classnames);
  467. for (MethodInfo minfo : methods) {
  468. String genericDesc = getGenericDesc(minfo);
  469. if (genericDesc != null)
  470. Descriptor.renameIncludeGenerics(genericDesc, classnames);
  471. else
  472. Descriptor.rename(minfo.getDescriptor(), classnames);
  473. AttributeInfo.getRefClasses(minfo.getAttributes(), classnames);
  474. }
  475. for (FieldInfo finfo : fields) {
  476. String desc = finfo.getDescriptor();
  477. Descriptor.rename(desc, classnames);
  478. AttributeInfo.getRefClasses(finfo.getAttributes(), classnames);
  479. }
  480. }
  481. /**
  482. * Returns the generic signature
  483. */
  484. private String getGenericDesc(MethodInfo methodInfo) {
  485. SignatureAttribute sa
  486. = (SignatureAttribute) methodInfo.getAttribute(SignatureAttribute.tag);
  487. return sa == null ? null : sa.getSignature();
  488. }
  489. /**
  490. * Returns the names of the interfaces implemented by the class.
  491. * The returned array is read only.
  492. */
  493. public String[] getInterfaces() {
  494. if (cachedInterfaces != null)
  495. return cachedInterfaces;
  496. String[] rtn = null;
  497. if (interfaces == null)
  498. rtn = new String[0];
  499. else {
  500. String[] list = new String[interfaces.length];
  501. for (int i = 0; i < interfaces.length; ++i)
  502. list[i] = constPool.getClassInfo(interfaces[i]);
  503. rtn = list;
  504. }
  505. cachedInterfaces = rtn;
  506. return rtn;
  507. }
  508. /**
  509. * Sets the interfaces.
  510. *
  511. * @param nameList
  512. * the names of the interfaces.
  513. */
  514. public void setInterfaces(String[] nameList) {
  515. cachedInterfaces = null;
  516. if (nameList != null) {
  517. interfaces = new int[nameList.length];
  518. for (int i = 0; i < nameList.length; ++i)
  519. interfaces[i] = constPool.addClassInfo(nameList[i]);
  520. }
  521. }
  522. /**
  523. * Appends an interface to the interfaces implemented by the class.
  524. */
  525. public void addInterface(String name) {
  526. cachedInterfaces = null;
  527. int info = constPool.addClassInfo(name);
  528. if (interfaces == null) {
  529. interfaces = new int[1];
  530. interfaces[0] = info;
  531. }
  532. else {
  533. int n = interfaces.length;
  534. int[] newarray = new int[n + 1];
  535. System.arraycopy(interfaces, 0, newarray, 0, n);
  536. newarray[n] = info;
  537. interfaces = newarray;
  538. }
  539. }
  540. /**
  541. * Returns all the fields declared in the class.
  542. *
  543. * @return a list of <code>FieldInfo</code>.
  544. * @see FieldInfo
  545. */
  546. public List<FieldInfo> getFields() {
  547. return fields;
  548. }
  549. /**
  550. * Appends a field to the class.
  551. *
  552. * @throws DuplicateMemberException when the field is already included.
  553. */
  554. public void addField(FieldInfo finfo) throws DuplicateMemberException {
  555. testExistingField(finfo.getName(), finfo.getDescriptor());
  556. fields.add(finfo);
  557. }
  558. /**
  559. * Just appends a field to the class.
  560. * It does not check field duplication.
  561. * Use this method only when minimizing performance overheads
  562. * is seriously required.
  563. *
  564. * @since 3.13
  565. */
  566. public final void addField2(FieldInfo finfo) {
  567. fields.add(finfo);
  568. }
  569. private void testExistingField(String name, String descriptor)
  570. throws DuplicateMemberException {
  571. for (FieldInfo minfo:fields)
  572. if (minfo.getName().equals(name))
  573. throw new DuplicateMemberException("duplicate field: " + name);
  574. }
  575. /**
  576. * Returns all the methods declared in the class.
  577. *
  578. * @return a list of <code>MethodInfo</code>.
  579. * @see MethodInfo
  580. */
  581. public List<MethodInfo> getMethods() {
  582. return methods;
  583. }
  584. /**
  585. * Returns the method with the specified name. If there are multiple methods
  586. * with that name, this method returns one of them.
  587. *
  588. * @return null if no such method is found.
  589. */
  590. public MethodInfo getMethod(String name) {
  591. for (MethodInfo minfo:methods)
  592. if (minfo.getName().equals(name))
  593. return minfo;
  594. return null;
  595. }
  596. /**
  597. * Returns a static initializer (class initializer), or null if it does not
  598. * exist.
  599. */
  600. public MethodInfo getStaticInitializer() {
  601. return getMethod(MethodInfo.nameClinit);
  602. }
  603. /**
  604. * Appends a method to the class.
  605. * If there is a bridge method with the same name and signature,
  606. * then the bridge method is removed before a new method is added.
  607. *
  608. * @throws DuplicateMemberException when the method is already included.
  609. */
  610. public void addMethod(MethodInfo minfo) throws DuplicateMemberException {
  611. testExistingMethod(minfo);
  612. methods.add(minfo);
  613. }
  614. /**
  615. * Just appends a method to the class.
  616. * It does not check method duplication or remove a bridge method.
  617. * Use this method only when minimizing performance overheads
  618. * is seriously required.
  619. *
  620. * @since 3.13
  621. */
  622. public final void addMethod2(MethodInfo minfo) {
  623. methods.add(minfo);
  624. }
  625. private void testExistingMethod(MethodInfo newMinfo)
  626. throws DuplicateMemberException
  627. {
  628. String name = newMinfo.getName();
  629. String descriptor = newMinfo.getDescriptor();
  630. ListIterator<MethodInfo> it = methods.listIterator(0);
  631. while (it.hasNext())
  632. if (isDuplicated(newMinfo, name, descriptor, it.next(), it))
  633. throw new DuplicateMemberException("duplicate method: " + name
  634. + " in " + this.getName());
  635. }
  636. private static boolean isDuplicated(MethodInfo newMethod, String newName,
  637. String newDesc, MethodInfo minfo,
  638. ListIterator<MethodInfo> it)
  639. {
  640. if (!minfo.getName().equals(newName))
  641. return false;
  642. String desc = minfo.getDescriptor();
  643. if (!Descriptor.eqParamTypes(desc, newDesc))
  644. return false;
  645. if (desc.equals(newDesc)) {
  646. if (notBridgeMethod(minfo))
  647. return true;
  648. // if the bridge method with the same signature
  649. // already exists, replace it.
  650. it.remove();
  651. return false;
  652. }
  653. return false;
  654. // return notBridgeMethod(minfo) && notBridgeMethod(newMethod);
  655. }
  656. /* For a bridge method, see Sec. 15.12.4.5 of JLS 3rd Ed.
  657. */
  658. private static boolean notBridgeMethod(MethodInfo minfo) {
  659. return (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0;
  660. }
  661. /**
  662. * Returns all the attributes. The returned <code>List</code> object
  663. * is shared with this object. If you add a new attribute to the list,
  664. * the attribute is also added to the classs file represented by this
  665. * object. If you remove an attribute from the list, it is also removed
  666. * from the class file.
  667. *
  668. * @return a list of <code>AttributeInfo</code> objects.
  669. * @see AttributeInfo
  670. */
  671. public List<AttributeInfo> getAttributes() {
  672. return attributes;
  673. }
  674. /**
  675. * Returns the attribute with the specified name. If there are multiple
  676. * attributes with that name, this method returns either of them. It
  677. * returns null if the specified attributed is not found.
  678. *
  679. * <p>An attribute name can be obtained by, for example,
  680. * {@link AnnotationsAttribute#visibleTag} or
  681. * {@link AnnotationsAttribute#invisibleTag}.
  682. * </p>
  683. *
  684. * @param name attribute name
  685. * @see #getAttributes()
  686. */
  687. public AttributeInfo getAttribute(String name) {
  688. for (AttributeInfo ai:attributes)
  689. if (ai.getName().equals(name))
  690. return ai;
  691. return null;
  692. }
  693. /**
  694. * Removes an attribute with the specified name.
  695. *
  696. * @param name attribute name.
  697. * @return the removed attribute or null.
  698. * @since 3.21
  699. */
  700. public AttributeInfo removeAttribute(String name) {
  701. return AttributeInfo.remove(attributes, name);
  702. }
  703. /**
  704. * Appends an attribute. If there is already an attribute with the same
  705. * name, the new one substitutes for it.
  706. *
  707. * @see #getAttributes()
  708. */
  709. public void addAttribute(AttributeInfo info) {
  710. AttributeInfo.remove(attributes, info.getName());
  711. attributes.add(info);
  712. }
  713. /**
  714. * Returns the source file containing this class.
  715. *
  716. * @return null if this information is not available.
  717. */
  718. public String getSourceFile() {
  719. SourceFileAttribute sf
  720. = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag);
  721. if (sf == null)
  722. return null;
  723. return sf.getFileName();
  724. }
  725. private void read(DataInputStream in) throws IOException {
  726. int i, n;
  727. int magic = in.readInt();
  728. if (magic != 0xCAFEBABE)
  729. throw new IOException("bad magic number: " + Integer.toHexString(magic));
  730. minor = in.readUnsignedShort();
  731. major = in.readUnsignedShort();
  732. constPool = new ConstPool(in);
  733. accessFlags = in.readUnsignedShort();
  734. thisClass = in.readUnsignedShort();
  735. constPool.setThisClassInfo(thisClass);
  736. superClass = in.readUnsignedShort();
  737. n = in.readUnsignedShort();
  738. if (n == 0)
  739. interfaces = null;
  740. else {
  741. interfaces = new int[n];
  742. for (i = 0; i < n; ++i)
  743. interfaces[i] = in.readUnsignedShort();
  744. }
  745. ConstPool cp = constPool;
  746. n = in.readUnsignedShort();
  747. fields = new ArrayList<FieldInfo>();
  748. for (i = 0; i < n; ++i)
  749. addField2(new FieldInfo(cp, in));
  750. n = in.readUnsignedShort();
  751. methods = new ArrayList<MethodInfo>();
  752. for (i = 0; i < n; ++i)
  753. addMethod2(new MethodInfo(cp, in));
  754. attributes = new ArrayList<AttributeInfo>();
  755. n = in.readUnsignedShort();
  756. for (i = 0; i < n; ++i)
  757. addAttribute(AttributeInfo.read(cp, in));
  758. thisclassname = constPool.getClassInfo(thisClass);
  759. }
  760. /**
  761. * Writes a class file represented by this object into an output stream.
  762. */
  763. public void write(DataOutputStream out) throws IOException {
  764. int i, n;
  765. out.writeInt(0xCAFEBABE); // magic
  766. out.writeShort(minor); // minor version
  767. out.writeShort(major); // major version
  768. constPool.write(out); // constant pool
  769. out.writeShort(accessFlags);
  770. out.writeShort(thisClass);
  771. out.writeShort(superClass);
  772. if (interfaces == null)
  773. n = 0;
  774. else
  775. n = interfaces.length;
  776. out.writeShort(n);
  777. for (i = 0; i < n; ++i)
  778. out.writeShort(interfaces[i]);
  779. n = fields.size();
  780. out.writeShort(n);
  781. for (i = 0; i < n; ++i) {
  782. FieldInfo finfo = fields.get(i);
  783. finfo.write(out);
  784. }
  785. out.writeShort(methods.size());
  786. for (MethodInfo minfo:methods)
  787. minfo.write(out);
  788. out.writeShort(attributes.size());
  789. AttributeInfo.writeAll(attributes, out);
  790. }
  791. /**
  792. * Get the Major version.
  793. *
  794. * @return the major version
  795. */
  796. public int getMajorVersion() {
  797. return major;
  798. }
  799. /**
  800. * Set the major version.
  801. *
  802. * @param major
  803. * the major version
  804. */
  805. public void setMajorVersion(int major) {
  806. this.major = major;
  807. }
  808. /**
  809. * Get the minor version.
  810. *
  811. * @return the minor version
  812. */
  813. public int getMinorVersion() {
  814. return minor;
  815. }
  816. /**
  817. * Set the minor version.
  818. *
  819. * @param minor
  820. * the minor version
  821. */
  822. public void setMinorVersion(int minor) {
  823. this.minor = minor;
  824. }
  825. /**
  826. * Sets the major and minor version to Java 5.
  827. *
  828. * If the major version is older than 49, Java 5
  829. * extensions such as annotations are ignored
  830. * by the JVM.
  831. */
  832. public void setVersionToJava5() {
  833. this.major = 49;
  834. this.minor = 0;
  835. }
  836. }