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 26KB

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