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.

JavaClass.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. package org.aspectj.apache.bcel.classfile;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import java.io.ByteArrayOutputStream;
  56. import java.io.DataOutputStream;
  57. import java.io.File;
  58. import java.io.FileOutputStream;
  59. import java.io.IOException;
  60. import java.io.OutputStream;
  61. import java.util.ArrayList;
  62. import java.util.Collection;
  63. import java.util.LinkedList;
  64. import java.util.List;
  65. import java.util.Queue;
  66. import java.util.StringTokenizer;
  67. import org.aspectj.apache.bcel.Constants;
  68. import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
  69. import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnos;
  70. import org.aspectj.apache.bcel.generic.Type;
  71. import org.aspectj.apache.bcel.util.SyntheticRepository;
  72. /**
  73. * Represents a Java class, i.e., the data structures, constant pool, fields, methods and commands contained in a Java .class file.
  74. * See <a href="ftp://java.sun.com/docs/specs/">JVM specification</a> for details.
  75. *
  76. * The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically
  77. * generating classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
  78. *
  79. * @version $Id: JavaClass.java,v 1.22 2009/09/15 19:40:14 aclement Exp $
  80. * @see org.aspectj.apache.bcel.generic.ClassGen
  81. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  82. */
  83. public class JavaClass extends Modifiers implements Cloneable, Node {
  84. private static final String[] NoInterfaceNames = new String[0];
  85. private static final Field[] NoFields = new Field[0];
  86. private static final Method[] NoMethod = new Method[0];
  87. private static final int[] NoInterfaceIndices = new int[0];
  88. private static final Attribute[] NoAttributes = new Attribute[0];
  89. private String fileName;
  90. private String packageName;
  91. private String sourcefileName;
  92. private int classnameIdx;
  93. private int superclassnameIdx;
  94. private String classname;
  95. private String superclassname;
  96. private int major, minor;
  97. private ConstantPool cpool;
  98. private int[] interfaces;
  99. private String[] interfacenames;
  100. private Field[] fields;
  101. private Method[] methods;
  102. private Attribute[] attributes;
  103. private AnnotationGen[] annotations;
  104. private boolean isGeneric = false;
  105. private boolean isAnonymous = false;
  106. private boolean isNested = false;
  107. private boolean computedNestedTypeStatus = false;
  108. // Annotations are collected from certain attributes, don't do it more than necessary!
  109. private boolean annotationsOutOfDate = true;
  110. // state for dealing with generic signature string
  111. private String signatureAttributeString = null;
  112. private Signature signatureAttribute = null;
  113. private boolean searchedForSignatureAttribute = false;
  114. /**
  115. * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any better.
  116. */
  117. private transient org.aspectj.apache.bcel.util.Repository repository = null;
  118. public JavaClass(int classnameIndex, int superclassnameIndex, String filename, int major, int minor, int access_flags,
  119. ConstantPool cpool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) {
  120. if (interfaces == null) {
  121. interfaces = NoInterfaceIndices;
  122. }
  123. this.classnameIdx = classnameIndex;
  124. this.superclassnameIdx = superclassnameIndex;
  125. this.fileName = filename;
  126. this.major = major;
  127. this.minor = minor;
  128. this.modifiers = access_flags;
  129. this.cpool = cpool;
  130. this.interfaces = interfaces;
  131. this.fields = (fields == null ? NoFields : fields);
  132. this.methods = (methods == null ? NoMethod : methods);
  133. this.attributes = (attributes == null ? NoAttributes : attributes);
  134. annotationsOutOfDate = true;
  135. // Get source file name if available
  136. SourceFile sfAttribute = AttributeUtils.getSourceFileAttribute(attributes);
  137. sourcefileName = sfAttribute == null ? "<Unknown>" : sfAttribute.getSourceFileName();
  138. /*
  139. * According to the specification the following entries must be of type `ConstantClass' but we check that anyway via the
  140. * `ConstPool.getConstant' method.
  141. */
  142. classname = cpool.getConstantString(classnameIndex, Constants.CONSTANT_Class);
  143. classname = Utility.compactClassName(classname, false);
  144. int index = classname.lastIndexOf('.');
  145. if (index < 0) {
  146. packageName = "";
  147. } else {
  148. packageName = classname.substring(0, index);
  149. }
  150. if (superclassnameIndex > 0) { // May be zero -> class is java.lang.Object
  151. superclassname = cpool.getConstantString(superclassnameIndex, Constants.CONSTANT_Class);
  152. superclassname = Utility.compactClassName(superclassname, false);
  153. } else {
  154. superclassname = "java.lang.Object";
  155. }
  156. if (interfaces.length == 0) {
  157. interfacenames = NoInterfaceNames;
  158. } else {
  159. interfacenames = new String[interfaces.length];
  160. for (int i = 0; i < interfaces.length; i++) {
  161. String str = cpool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
  162. interfacenames[i] = Utility.compactClassName(str, false);
  163. }
  164. }
  165. }
  166. /**
  167. * Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class. I.e., the
  168. * hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  169. *
  170. * @param v Visitor object
  171. */
  172. public void accept(ClassVisitor v) {
  173. v.visitJavaClass(this);
  174. }
  175. /**
  176. * Dump class to a file.
  177. *
  178. * @param file Output file
  179. * @throws IOException
  180. */
  181. public void dump(File file) throws IOException {
  182. String parent = file.getParent();
  183. if (parent != null) {
  184. File dir = new File(parent);
  185. dir.mkdirs();
  186. }
  187. dump(new DataOutputStream(new FileOutputStream(file)));
  188. }
  189. /**
  190. * Dump class to a file named file_name.
  191. *
  192. * @param file_name Output file name
  193. * @exception IOException
  194. */
  195. public void dump(String file_name) throws IOException {
  196. dump(new File(file_name));
  197. }
  198. /**
  199. * @return class in binary format
  200. */
  201. public byte[] getBytes() {
  202. ByteArrayOutputStream s = new ByteArrayOutputStream();
  203. DataOutputStream ds = new DataOutputStream(s);
  204. try {
  205. dump(ds);
  206. } catch (IOException e) {
  207. e.printStackTrace();
  208. } finally {
  209. try {
  210. ds.close();
  211. } catch (IOException e2) {
  212. e2.printStackTrace();
  213. }
  214. }
  215. return s.toByteArray();
  216. }
  217. /**
  218. * Dump Java class to output stream in binary format.
  219. */
  220. public void dump(OutputStream file) throws IOException {
  221. dump(new DataOutputStream(file));
  222. }
  223. /**
  224. * Dump Java class to output stream in binary format.
  225. */
  226. public void dump(DataOutputStream file) throws IOException {
  227. file.writeInt(0xcafebabe);
  228. file.writeShort(minor);
  229. file.writeShort(major);
  230. cpool.dump(file);
  231. file.writeShort(modifiers);
  232. file.writeShort(classnameIdx);
  233. file.writeShort(superclassnameIdx);
  234. file.writeShort(interfaces.length);
  235. for (int i = 0; i < interfaces.length; i++) {
  236. file.writeShort(interfaces[i]);
  237. }
  238. file.writeShort(fields.length);
  239. for (int i = 0; i < fields.length; i++) {
  240. fields[i].dump(file);
  241. }
  242. file.writeShort(methods.length);
  243. for (int i = 0; i < methods.length; i++) {
  244. methods[i].dump(file);
  245. }
  246. AttributeUtils.writeAttributes(attributes, file);
  247. file.close();
  248. }
  249. public Attribute[] getAttributes() {
  250. return attributes;
  251. }
  252. public AnnotationGen[] getAnnotations() {
  253. if (annotationsOutOfDate) {
  254. // Find attributes that contain annotation data
  255. List<AnnotationGen> accumulatedAnnotations = new ArrayList<AnnotationGen>();
  256. for (int i = 0; i < attributes.length; i++) {
  257. Attribute attribute = attributes[i];
  258. if (attribute instanceof RuntimeAnnos) {
  259. RuntimeAnnos runtimeAnnotations = (RuntimeAnnos) attribute;
  260. accumulatedAnnotations.addAll(runtimeAnnotations.getAnnotations());
  261. }
  262. }
  263. annotations = accumulatedAnnotations.toArray(new AnnotationGen[] {});
  264. annotationsOutOfDate = false;
  265. }
  266. return annotations;
  267. }
  268. /**
  269. * @return Class name.
  270. */
  271. public String getClassName() {
  272. return classname;
  273. }
  274. /**
  275. * @return Package name.
  276. */
  277. public String getPackageName() {
  278. return packageName;
  279. }
  280. public int getClassNameIndex() {
  281. return classnameIdx;
  282. }
  283. public ConstantPool getConstantPool() {
  284. return cpool;
  285. }
  286. /**
  287. * @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are those
  288. * specific to this class, and not those of the superclass or superinterfaces.
  289. */
  290. public Field[] getFields() {
  291. return fields;
  292. }
  293. /**
  294. * @return File name of class, aka SourceFile attribute value
  295. */
  296. public String getFileName() {
  297. return fileName;
  298. }
  299. /**
  300. * @return Names of implemented interfaces.
  301. */
  302. public String[] getInterfaceNames() {
  303. return interfacenames;
  304. }
  305. /**
  306. * @return Indices in constant pool of implemented interfaces.
  307. */
  308. public int[] getInterfaceIndices() {
  309. return interfaces;
  310. }
  311. public int getMajor() {
  312. return major;
  313. }
  314. /**
  315. * @return Methods of the class.
  316. */
  317. public Method[] getMethods() {
  318. return methods;
  319. }
  320. /**
  321. * @return A org.aspectj.apache.bcel.classfile.Method corresponding to java.lang.reflect.Method if any
  322. */
  323. public Method getMethod(java.lang.reflect.Method m) {
  324. for (int i = 0; i < methods.length; i++) {
  325. Method method = methods[i];
  326. if (m.getName().equals(method.getName()) && m.getModifiers() == method.getModifiers()
  327. && Type.getSignature(m).equals(method.getSignature())) {
  328. return method;
  329. }
  330. }
  331. return null;
  332. }
  333. public Method getMethod(java.lang.reflect.Constructor<?> c) {
  334. for (int i = 0; i < methods.length; i++) {
  335. Method method = methods[i];
  336. if (method.getName().equals("<init>") && c.getModifiers() == method.getModifiers()
  337. && Type.getSignature(c).equals(method.getSignature())) {
  338. return method;
  339. }
  340. }
  341. return null;
  342. }
  343. public Field getField(java.lang.reflect.Field field) {
  344. String fieldName = field.getName();
  345. for (Field f : fields) {
  346. if (f.getName().equals(fieldName)) {
  347. return f;
  348. }
  349. }
  350. return null;
  351. }
  352. /**
  353. * @return Minor number of class file version.
  354. */
  355. public int getMinor() {
  356. return minor;
  357. }
  358. /**
  359. * @return sbsolute path to file where this class was read from
  360. */
  361. public String getSourceFileName() {
  362. return sourcefileName;
  363. }
  364. /**
  365. * @return Superclass name.
  366. */
  367. public String getSuperclassName() {
  368. return superclassname;
  369. }
  370. /**
  371. * @return Class name index.
  372. */
  373. public int getSuperclassNameIndex() {
  374. return superclassnameIdx;
  375. }
  376. /**
  377. * @param attributes .
  378. */
  379. public void setAttributes(Attribute[] attributes) {
  380. this.attributes = attributes;
  381. annotationsOutOfDate = true;
  382. }
  383. /**
  384. * @param class_name .
  385. */
  386. public void setClassName(String class_name) {
  387. this.classname = class_name;
  388. }
  389. /**
  390. * @param class_name_index .
  391. */
  392. public void setClassNameIndex(int class_name_index) {
  393. this.classnameIdx = class_name_index;
  394. }
  395. /**
  396. * @param constant_pool .
  397. */
  398. public void setConstantPool(ConstantPool constant_pool) {
  399. this.cpool = constant_pool;
  400. }
  401. /**
  402. * @param fields .
  403. */
  404. public void setFields(Field[] fields) {
  405. this.fields = fields;
  406. }
  407. /**
  408. * Set File name of class, aka SourceFile attribute value
  409. */
  410. public void setFileName(String file_name) {
  411. this.fileName = file_name;
  412. }
  413. /**
  414. * @param interface_names .
  415. */
  416. public void setInterfaceNames(String[] interface_names) {
  417. this.interfacenames = interface_names;
  418. }
  419. /**
  420. * @param interfaces .
  421. */
  422. public void setInterfaces(int[] interfaces) {
  423. this.interfaces = interfaces;
  424. }
  425. public void setMajor(int major) {
  426. this.major = major;
  427. }
  428. public void setMethods(Method[] methods) {
  429. this.methods = methods;
  430. }
  431. public void setMinor(int minor) {
  432. this.minor = minor;
  433. }
  434. /**
  435. * Set absolute path to file this class was read from.
  436. */
  437. public void setSourceFileName(String source_file_name) {
  438. this.sourcefileName = source_file_name;
  439. }
  440. /**
  441. * @param superclass_name .
  442. */
  443. public void setSuperclassName(String superclass_name) {
  444. this.superclassname = superclass_name;
  445. }
  446. /**
  447. * @param superclass_name_index .
  448. */
  449. public void setSuperclassNameIndex(int superclass_name_index) {
  450. this.superclassnameIdx = superclass_name_index;
  451. }
  452. /**
  453. * @return String representing class contents.
  454. */
  455. @Override
  456. public String toString() {
  457. String access = Utility.accessToString(modifiers, true);
  458. access = access.equals("") ? "" : access + " ";
  459. StringBuffer buf = new StringBuffer(access + Utility.classOrInterface(modifiers) + " " + classname + " extends "
  460. + Utility.compactClassName(superclassname, false) + '\n');
  461. int size = interfaces.length;
  462. if (size > 0) {
  463. buf.append("implements\t\t");
  464. for (int i = 0; i < size; i++) {
  465. buf.append(interfacenames[i]);
  466. if (i < size - 1) {
  467. buf.append(", ");
  468. }
  469. }
  470. buf.append('\n');
  471. }
  472. buf.append("filename\t\t" + fileName + '\n');
  473. buf.append("compiled from\t\t" + sourcefileName + '\n');
  474. buf.append("compiler version\t" + major + "." + minor + '\n');
  475. buf.append("access flags\t\t" + modifiers + '\n');
  476. buf.append("constant pool\t\t" + cpool.getLength() + " entries\n");
  477. buf.append("ACC_SUPER flag\t\t" + isSuper() + "\n");
  478. if (attributes.length > 0) {
  479. buf.append("\nAttribute(s):\n");
  480. for (int i = 0; i < attributes.length; i++) {
  481. buf.append(indent(attributes[i]));
  482. }
  483. }
  484. if (annotations != null && annotations.length > 0) {
  485. buf.append("\nAnnotation(s):\n");
  486. for (int i = 0; i < annotations.length; i++) {
  487. buf.append(indent(annotations[i]));
  488. }
  489. }
  490. if (fields.length > 0) {
  491. buf.append("\n" + fields.length + " fields:\n");
  492. for (int i = 0; i < fields.length; i++) {
  493. buf.append("\t" + fields[i] + '\n');
  494. }
  495. }
  496. if (methods.length > 0) {
  497. buf.append("\n" + methods.length + " methods:\n");
  498. for (int i = 0; i < methods.length; i++) {
  499. buf.append("\t" + methods[i] + '\n');
  500. }
  501. }
  502. return buf.toString();
  503. }
  504. private static final String indent(Object obj) {
  505. StringTokenizer tok = new StringTokenizer(obj.toString(), "\n");
  506. StringBuffer buf = new StringBuffer();
  507. while (tok.hasMoreTokens()) {
  508. buf.append("\t" + tok.nextToken() + "\n");
  509. }
  510. return buf.toString();
  511. }
  512. public final boolean isSuper() {
  513. return (modifiers & Constants.ACC_SUPER) != 0;
  514. }
  515. public final boolean isClass() {
  516. return (modifiers & Constants.ACC_INTERFACE) == 0;
  517. }
  518. public final boolean isAnonymous() {
  519. computeNestedTypeStatus();
  520. return this.isAnonymous;
  521. }
  522. public final boolean isNested() {
  523. computeNestedTypeStatus();
  524. return this.isNested;
  525. }
  526. private final void computeNestedTypeStatus() {
  527. if (computedNestedTypeStatus) {
  528. return;
  529. }
  530. // Attribute[] attrs = attributes.getAttributes();
  531. for (int i = 0; i < attributes.length; i++) {
  532. if (attributes[i] instanceof InnerClasses) {
  533. InnerClass[] innerClasses = ((InnerClasses) attributes[i]).getInnerClasses();
  534. for (int j = 0; j < innerClasses.length; j++) {
  535. boolean innerClassAttributeRefersToMe = false;
  536. String inner_class_name = cpool.getConstantString(innerClasses[j].getInnerClassIndex(),
  537. Constants.CONSTANT_Class);
  538. inner_class_name = Utility.compactClassName(inner_class_name);
  539. if (inner_class_name.equals(getClassName())) {
  540. innerClassAttributeRefersToMe = true;
  541. }
  542. if (innerClassAttributeRefersToMe) {
  543. this.isNested = true;
  544. if (innerClasses[j].getInnerNameIndex() == 0) {
  545. this.isAnonymous = true;
  546. }
  547. }
  548. }
  549. }
  550. }
  551. this.computedNestedTypeStatus = true;
  552. }
  553. // J5SUPPORT:
  554. /**
  555. * Returns true if this class represents an annotation, i.e. it was a 'public @interface blahblah' declaration
  556. */
  557. public final boolean isAnnotation() {
  558. return (modifiers & Constants.ACC_ANNOTATION) != 0;
  559. }
  560. /**
  561. * Returns true if this class represents an enum type
  562. */
  563. public final boolean isEnum() {
  564. return (modifiers & Constants.ACC_ENUM) != 0;
  565. }
  566. /********************* New repository functionality *********************/
  567. /**
  568. * Gets the ClassRepository which holds its definition. By default this is the same as SyntheticRepository.getInstance();
  569. */
  570. public org.aspectj.apache.bcel.util.Repository getRepository() {
  571. if (repository == null) {
  572. repository = SyntheticRepository.getInstance();
  573. }
  574. return repository;
  575. }
  576. /**
  577. * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
  578. */
  579. public void setRepository(org.aspectj.apache.bcel.util.Repository repository) {
  580. this.repository = repository;
  581. }
  582. /**
  583. * Equivalent to runtime "instanceof" operator.
  584. *
  585. * @return true if this JavaClass is derived from teh super class
  586. */
  587. public final boolean instanceOf(JavaClass super_class) {
  588. if (this.equals(super_class)) {
  589. return true;
  590. }
  591. JavaClass[] super_classes = getSuperClasses();
  592. for (int i = 0; i < super_classes.length; i++) {
  593. if (super_classes[i].equals(super_class)) {
  594. return true;
  595. }
  596. }
  597. if (super_class.isInterface()) {
  598. return implementationOf(super_class);
  599. }
  600. return false;
  601. }
  602. /**
  603. * @return true, if clazz is an implementation of interface inter
  604. */
  605. public boolean implementationOf(JavaClass inter) {
  606. if (!inter.isInterface()) {
  607. throw new IllegalArgumentException(inter.getClassName() + " is no interface");
  608. }
  609. if (this.equals(inter)) {
  610. return true;
  611. }
  612. Collection<JavaClass> superInterfaces = getAllInterfaces();
  613. for (JavaClass superInterface : superInterfaces) {
  614. if (superInterface.equals(inter)) {
  615. return true;
  616. }
  617. }
  618. // for (int i = 0; i < super_interfaces.length; i++) {
  619. // if (super_interfaces[i].equals(inter)) {
  620. // return true;
  621. // }
  622. // }
  623. return false;
  624. }
  625. /**
  626. * @return the superclass for this JavaClass object, or null if this is java.lang.Object
  627. */
  628. public JavaClass getSuperClass() {
  629. if ("java.lang.Object".equals(getClassName())) {
  630. return null;
  631. }
  632. try {
  633. return getRepository().loadClass(getSuperclassName());
  634. } catch (ClassNotFoundException e) {
  635. System.err.println(e);
  636. return null;
  637. }
  638. }
  639. /**
  640. * @return list of super classes of this class in ascending order, i.e., java.lang.Object is always the last element
  641. */
  642. public JavaClass[] getSuperClasses() {
  643. JavaClass clazz = this;
  644. List<JavaClass> vec = new ArrayList<JavaClass>();
  645. for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
  646. vec.add(clazz);
  647. }
  648. return vec.toArray(new JavaClass[vec.size()]);
  649. }
  650. /**
  651. * Get interfaces directly implemented by this JavaClass.
  652. */
  653. public JavaClass[] getInterfaces() {
  654. String[] interfaces = getInterfaceNames();
  655. JavaClass[] classes = new JavaClass[interfaces.length];
  656. try {
  657. for (int i = 0; i < interfaces.length; i++) {
  658. classes[i] = getRepository().loadClass(interfaces[i]);
  659. }
  660. } catch (ClassNotFoundException e) {
  661. System.err.println(e);
  662. return null;
  663. }
  664. return classes;
  665. }
  666. /**
  667. * Get all interfaces implemented by this JavaClass (transitively).
  668. */
  669. public Collection<JavaClass> getAllInterfaces() {
  670. Queue<JavaClass> queue = new LinkedList<JavaClass>();
  671. List<JavaClass> interfaceList = new ArrayList<JavaClass>();
  672. queue.add(this);
  673. while (!queue.isEmpty()) {
  674. JavaClass clazz = queue.remove();
  675. JavaClass souper = clazz.getSuperClass();
  676. JavaClass[] interfaces = clazz.getInterfaces();
  677. if (clazz.isInterface()) {
  678. interfaceList.add(clazz);
  679. } else {
  680. if (souper != null) {
  681. queue.add(souper);
  682. }
  683. }
  684. for (int i = 0; i < interfaces.length; i++) {
  685. queue.add(interfaces[i]);
  686. }
  687. }
  688. return interfaceList;
  689. // return interfaceList.toArray(new JavaClass[interfaceList.size()]);
  690. }
  691. /**
  692. * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
  693. * Ljava/util/Vector; the signature attribute will tell us e.g. "<E:>Ljava/lang/Object". We can learn the type variable names,
  694. * their bounds, and the true superclass and superinterface types (including any parameterizations) Coded for performance -
  695. * searches for the attribute only when requested - only searches for it once.
  696. */
  697. public final String getGenericSignature() {
  698. loadGenericSignatureInfoIfNecessary();
  699. return signatureAttributeString;
  700. }
  701. public boolean isGeneric() {
  702. loadGenericSignatureInfoIfNecessary();
  703. return isGeneric;
  704. }
  705. private void loadGenericSignatureInfoIfNecessary() {
  706. if (!searchedForSignatureAttribute) {
  707. signatureAttribute = AttributeUtils.getSignatureAttribute(attributes);
  708. signatureAttributeString = signatureAttribute == null ? null : signatureAttribute.getSignature();
  709. isGeneric = signatureAttribute != null && signatureAttributeString.charAt(0) == '<';
  710. searchedForSignatureAttribute = true;
  711. }
  712. }
  713. public final Signature getSignatureAttribute() {
  714. loadGenericSignatureInfoIfNecessary();
  715. return signatureAttribute;
  716. }
  717. }