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

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