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.

ClassFile.java 28KB

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