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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  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. * Returns the names of the interfaces implemented by the class.
  462. * The returned array is read only.
  463. */
  464. public String[] getInterfaces() {
  465. if (cachedInterfaces != null)
  466. return cachedInterfaces;
  467. String[] rtn = null;
  468. if (interfaces == null)
  469. rtn = new String[0];
  470. else {
  471. String[] list = new String[interfaces.length];
  472. for (int i = 0; i < interfaces.length; ++i)
  473. list[i] = constPool.getClassInfo(interfaces[i]);
  474. rtn = list;
  475. }
  476. cachedInterfaces = rtn;
  477. return rtn;
  478. }
  479. /**
  480. * Sets the interfaces.
  481. *
  482. * @param nameList
  483. * the names of the interfaces.
  484. */
  485. public void setInterfaces(String[] nameList) {
  486. cachedInterfaces = null;
  487. if (nameList != null) {
  488. interfaces = new int[nameList.length];
  489. for (int i = 0; i < nameList.length; ++i)
  490. interfaces[i] = constPool.addClassInfo(nameList[i]);
  491. }
  492. }
  493. /**
  494. * Appends an interface to the interfaces implemented by the class.
  495. */
  496. public void addInterface(String name) {
  497. cachedInterfaces = null;
  498. int info = constPool.addClassInfo(name);
  499. if (interfaces == null) {
  500. interfaces = new int[1];
  501. interfaces[0] = info;
  502. }
  503. else {
  504. int n = interfaces.length;
  505. int[] newarray = new int[n + 1];
  506. System.arraycopy(interfaces, 0, newarray, 0, n);
  507. newarray[n] = info;
  508. interfaces = newarray;
  509. }
  510. }
  511. /**
  512. * Returns all the fields declared in the class.
  513. *
  514. * @return a list of <code>FieldInfo</code>.
  515. * @see FieldInfo
  516. */
  517. public List<FieldInfo> getFields() {
  518. return fields;
  519. }
  520. /**
  521. * Appends a field to the class.
  522. *
  523. * @throws DuplicateMemberException when the field is already included.
  524. */
  525. public void addField(FieldInfo finfo) throws DuplicateMemberException {
  526. testExistingField(finfo.getName(), finfo.getDescriptor());
  527. fields.add(finfo);
  528. }
  529. /**
  530. * Just appends a field to the class.
  531. * It does not check field duplication.
  532. * Use this method only when minimizing performance overheads
  533. * is seriously required.
  534. *
  535. * @since 3.13
  536. */
  537. public final void addField2(FieldInfo finfo) {
  538. fields.add(finfo);
  539. }
  540. private void testExistingField(String name, String descriptor)
  541. throws DuplicateMemberException {
  542. for (FieldInfo minfo:fields)
  543. if (minfo.getName().equals(name))
  544. throw new DuplicateMemberException("duplicate field: " + name);
  545. }
  546. /**
  547. * Returns all the methods declared in the class.
  548. *
  549. * @return a list of <code>MethodInfo</code>.
  550. * @see MethodInfo
  551. */
  552. public List<MethodInfo> getMethods() {
  553. return methods;
  554. }
  555. /**
  556. * Returns the method with the specified name. If there are multiple methods
  557. * with that name, this method returns one of them.
  558. *
  559. * @return null if no such method is found.
  560. */
  561. public MethodInfo getMethod(String name) {
  562. for (MethodInfo minfo:methods)
  563. if (minfo.getName().equals(name))
  564. return minfo;
  565. return null;
  566. }
  567. /**
  568. * Returns a static initializer (class initializer), or null if it does not
  569. * exist.
  570. */
  571. public MethodInfo getStaticInitializer() {
  572. return getMethod(MethodInfo.nameClinit);
  573. }
  574. /**
  575. * Appends a method to the class.
  576. * If there is a bridge method with the same name and signature,
  577. * then the bridge method is removed before a new method is added.
  578. *
  579. * @throws DuplicateMemberException when the method is already included.
  580. */
  581. public void addMethod(MethodInfo minfo) throws DuplicateMemberException {
  582. testExistingMethod(minfo);
  583. methods.add(minfo);
  584. }
  585. /**
  586. * Just appends a method to the class.
  587. * It does not check method duplication or remove a bridge method.
  588. * Use this method only when minimizing performance overheads
  589. * is seriously required.
  590. *
  591. * @since 3.13
  592. */
  593. public final void addMethod2(MethodInfo minfo) {
  594. methods.add(minfo);
  595. }
  596. private void testExistingMethod(MethodInfo newMinfo)
  597. throws DuplicateMemberException
  598. {
  599. String name = newMinfo.getName();
  600. String descriptor = newMinfo.getDescriptor();
  601. ListIterator<MethodInfo> it = methods.listIterator(0);
  602. while (it.hasNext())
  603. if (isDuplicated(newMinfo, name, descriptor, it.next(), it))
  604. throw new DuplicateMemberException("duplicate method: " + name
  605. + " in " + this.getName());
  606. }
  607. private static boolean isDuplicated(MethodInfo newMethod, String newName,
  608. String newDesc, MethodInfo minfo,
  609. ListIterator<MethodInfo> it)
  610. {
  611. if (!minfo.getName().equals(newName))
  612. return false;
  613. String desc = minfo.getDescriptor();
  614. if (!Descriptor.eqParamTypes(desc, newDesc))
  615. return false;
  616. if (desc.equals(newDesc)) {
  617. if (notBridgeMethod(minfo))
  618. return true;
  619. // if the bridge method with the same signature
  620. // already exists, replace it.
  621. it.remove();
  622. return false;
  623. }
  624. return false;
  625. // return notBridgeMethod(minfo) && notBridgeMethod(newMethod);
  626. }
  627. /* For a bridge method, see Sec. 15.12.4.5 of JLS 3rd Ed.
  628. */
  629. private static boolean notBridgeMethod(MethodInfo minfo) {
  630. return (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0;
  631. }
  632. /**
  633. * Returns all the attributes. The returned <code>List</code> object
  634. * is shared with this object. If you add a new attribute to the list,
  635. * the attribute is also added to the classs file represented by this
  636. * object. If you remove an attribute from the list, it is also removed
  637. * from the class file.
  638. *
  639. * @return a list of <code>AttributeInfo</code> objects.
  640. * @see AttributeInfo
  641. */
  642. public List<AttributeInfo> getAttributes() {
  643. return attributes;
  644. }
  645. /**
  646. * Returns the attribute with the specified name. If there are multiple
  647. * attributes with that name, this method returns either of them. It
  648. * returns null if the specified attributed is not found.
  649. *
  650. * <p>An attribute name can be obtained by, for example,
  651. * {@link AnnotationsAttribute#visibleTag} or
  652. * {@link AnnotationsAttribute#invisibleTag}.
  653. * </p>
  654. *
  655. * @param name attribute name
  656. * @see #getAttributes()
  657. */
  658. public AttributeInfo getAttribute(String name) {
  659. for (AttributeInfo ai:attributes)
  660. if (ai.getName().equals(name))
  661. return ai;
  662. return null;
  663. }
  664. /**
  665. * Removes an attribute with the specified name.
  666. *
  667. * @param name attribute name.
  668. * @return the removed attribute or null.
  669. * @since 3.21
  670. */
  671. public AttributeInfo removeAttribute(String name) {
  672. return AttributeInfo.remove(attributes, name);
  673. }
  674. /**
  675. * Appends an attribute. If there is already an attribute with the same
  676. * name, the new one substitutes for it.
  677. *
  678. * @see #getAttributes()
  679. */
  680. public void addAttribute(AttributeInfo info) {
  681. AttributeInfo.remove(attributes, info.getName());
  682. attributes.add(info);
  683. }
  684. /**
  685. * Returns the source file containing this class.
  686. *
  687. * @return null if this information is not available.
  688. */
  689. public String getSourceFile() {
  690. SourceFileAttribute sf
  691. = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag);
  692. if (sf == null)
  693. return null;
  694. return sf.getFileName();
  695. }
  696. private void read(DataInputStream in) throws IOException {
  697. int i, n;
  698. int magic = in.readInt();
  699. if (magic != 0xCAFEBABE)
  700. throw new IOException("bad magic number: " + Integer.toHexString(magic));
  701. minor = in.readUnsignedShort();
  702. major = in.readUnsignedShort();
  703. constPool = new ConstPool(in);
  704. accessFlags = in.readUnsignedShort();
  705. thisClass = in.readUnsignedShort();
  706. constPool.setThisClassInfo(thisClass);
  707. superClass = in.readUnsignedShort();
  708. n = in.readUnsignedShort();
  709. if (n == 0)
  710. interfaces = null;
  711. else {
  712. interfaces = new int[n];
  713. for (i = 0; i < n; ++i)
  714. interfaces[i] = in.readUnsignedShort();
  715. }
  716. ConstPool cp = constPool;
  717. n = in.readUnsignedShort();
  718. fields = new ArrayList<FieldInfo>();
  719. for (i = 0; i < n; ++i)
  720. addField2(new FieldInfo(cp, in));
  721. n = in.readUnsignedShort();
  722. methods = new ArrayList<MethodInfo>();
  723. for (i = 0; i < n; ++i)
  724. addMethod2(new MethodInfo(cp, in));
  725. attributes = new ArrayList<AttributeInfo>();
  726. n = in.readUnsignedShort();
  727. for (i = 0; i < n; ++i)
  728. addAttribute(AttributeInfo.read(cp, in));
  729. thisclassname = constPool.getClassInfo(thisClass);
  730. }
  731. /**
  732. * Writes a class file represented by this object into an output stream.
  733. */
  734. public void write(DataOutputStream out) throws IOException {
  735. int i, n;
  736. out.writeInt(0xCAFEBABE); // magic
  737. out.writeShort(minor); // minor version
  738. out.writeShort(major); // major version
  739. constPool.write(out); // constant pool
  740. out.writeShort(accessFlags);
  741. out.writeShort(thisClass);
  742. out.writeShort(superClass);
  743. if (interfaces == null)
  744. n = 0;
  745. else
  746. n = interfaces.length;
  747. out.writeShort(n);
  748. for (i = 0; i < n; ++i)
  749. out.writeShort(interfaces[i]);
  750. n = fields.size();
  751. out.writeShort(n);
  752. for (i = 0; i < n; ++i) {
  753. FieldInfo finfo = fields.get(i);
  754. finfo.write(out);
  755. }
  756. out.writeShort(methods.size());
  757. for (MethodInfo minfo:methods)
  758. minfo.write(out);
  759. out.writeShort(attributes.size());
  760. AttributeInfo.writeAll(attributes, out);
  761. }
  762. /**
  763. * Get the Major version.
  764. *
  765. * @return the major version
  766. */
  767. public int getMajorVersion() {
  768. return major;
  769. }
  770. /**
  771. * Set the major version.
  772. *
  773. * @param major
  774. * the major version
  775. */
  776. public void setMajorVersion(int major) {
  777. this.major = major;
  778. }
  779. /**
  780. * Get the minor version.
  781. *
  782. * @return the minor version
  783. */
  784. public int getMinorVersion() {
  785. return minor;
  786. }
  787. /**
  788. * Set the minor version.
  789. *
  790. * @param minor
  791. * the minor version
  792. */
  793. public void setMinorVersion(int minor) {
  794. this.minor = minor;
  795. }
  796. /**
  797. * Sets the major and minor version to Java 5.
  798. *
  799. * If the major version is older than 49, Java 5
  800. * extensions such as annotations are ignored
  801. * by the JVM.
  802. */
  803. public void setVersionToJava5() {
  804. this.major = 49;
  805. this.minor = 0;
  806. }
  807. }