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.

CtClassType.java 41KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2006 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. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist;
  16. import java.io.BufferedInputStream;
  17. import java.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.net.URL;
  22. import java.util.ArrayList;
  23. import java.util.Enumeration;
  24. import java.util.HashMap;
  25. import java.util.Hashtable;
  26. import java.util.List;
  27. import java.util.Set;
  28. import javassist.bytecode.AccessFlag;
  29. import javassist.bytecode.AttributeInfo;
  30. import javassist.bytecode.AnnotationsAttribute;
  31. import javassist.bytecode.BadBytecode;
  32. import javassist.bytecode.Bytecode;
  33. import javassist.bytecode.ClassFile;
  34. import javassist.bytecode.CodeAttribute;
  35. import javassist.bytecode.ConstantAttribute;
  36. import javassist.bytecode.CodeIterator;
  37. import javassist.bytecode.ConstPool;
  38. import javassist.bytecode.Descriptor;
  39. import javassist.bytecode.EnclosingMethodAttribute;
  40. import javassist.bytecode.FieldInfo;
  41. import javassist.bytecode.InnerClassesAttribute;
  42. import javassist.bytecode.MethodInfo;
  43. import javassist.bytecode.annotation.Annotation;
  44. import javassist.compiler.AccessorMaker;
  45. import javassist.compiler.CompileError;
  46. import javassist.compiler.Javac;
  47. import javassist.expr.ExprEditor;
  48. /**
  49. * Class types.
  50. */
  51. class CtClassType extends CtClass {
  52. ClassPool classPool;
  53. boolean wasChanged;
  54. private boolean wasFrozen;
  55. boolean wasPruned;
  56. boolean memberRemoved;
  57. ClassFile classfile;
  58. private CtMember fieldsCache;
  59. private CtMember methodsCache;
  60. private CtMember constructorsCache;
  61. private CtConstructor classInitializerCache;
  62. private AccessorMaker accessors;
  63. private FieldInitLink fieldInitializers;
  64. private Hashtable hiddenMethods; // must be synchronous
  65. private int uniqueNumberSeed;
  66. private boolean doPruning = ClassPool.doPruning;
  67. int getCounter;
  68. private static int readCounter = 0;
  69. private static final int READ_THRESHOLD = 100; // see getClassFile2()
  70. CtClassType(String name, ClassPool cp) {
  71. super(name);
  72. classPool = cp;
  73. wasChanged = wasFrozen = wasPruned = memberRemoved = false;
  74. classfile = null;
  75. accessors = null;
  76. fieldInitializers = null;
  77. hiddenMethods = null;
  78. uniqueNumberSeed = 0;
  79. eraseCache();
  80. getCounter = 0;
  81. }
  82. CtClassType(InputStream ins, ClassPool cp) throws IOException {
  83. this((String)null, cp);
  84. classfile = new ClassFile(new DataInputStream(ins));
  85. qualifiedName = classfile.getName();
  86. }
  87. protected void extendToString(StringBuffer buffer) {
  88. if (wasChanged)
  89. buffer.append("changed ");
  90. if (wasFrozen)
  91. buffer.append("frozen ");
  92. if (wasPruned)
  93. buffer.append("pruned ");
  94. buffer.append(Modifier.toString(getModifiers()));
  95. buffer.append(" class ");
  96. buffer.append(getName());
  97. try {
  98. CtClass ext = getSuperclass();
  99. if (ext != null) {
  100. String name = ext.getName();
  101. if (!name.equals("java.lang.Object"))
  102. buffer.append(" extends " + ext.getName());
  103. }
  104. }
  105. catch (NotFoundException e) {
  106. buffer.append(" extends ??");
  107. }
  108. try {
  109. CtClass[] intf = getInterfaces();
  110. if (intf.length > 0)
  111. buffer.append(" implements ");
  112. for (int i = 0; i < intf.length; ++i) {
  113. buffer.append(intf[i].getName());
  114. buffer.append(", ");
  115. }
  116. }
  117. catch (NotFoundException e) {
  118. buffer.append(" extends ??");
  119. }
  120. CtMember field = getFieldsCache();
  121. buffer.append(" fields=");
  122. while (field != null) {
  123. buffer.append(field);
  124. buffer.append(", ");
  125. field = field.next;
  126. }
  127. CtMember c = getConstructorsCache();
  128. buffer.append(" constructors=");
  129. while (c != null) {
  130. buffer.append(c);
  131. buffer.append(", ");
  132. c = c.next;
  133. }
  134. CtMember m = getMethodsCache();
  135. buffer.append(" methods=");
  136. while (m != null) {
  137. buffer.append(m);
  138. buffer.append(", ");
  139. m = m.next;
  140. }
  141. }
  142. protected void eraseCache() {
  143. fieldsCache = null;
  144. constructorsCache = null;
  145. classInitializerCache = null;
  146. methodsCache = null;
  147. }
  148. public AccessorMaker getAccessorMaker() {
  149. if (accessors == null)
  150. accessors = new AccessorMaker(this);
  151. return accessors;
  152. }
  153. public ClassFile getClassFile2() {
  154. if (classfile != null)
  155. return classfile;
  156. if (readCounter++ > READ_THRESHOLD
  157. && ClassPool.releaseUnmodifiedClassFile) {
  158. releaseClassFiles();
  159. readCounter = 0;
  160. }
  161. InputStream fin = null;
  162. try {
  163. fin = classPool.openClassfile(getName());
  164. if (fin == null)
  165. throw new NotFoundException(getName());
  166. fin = new BufferedInputStream(fin);
  167. classfile = new ClassFile(new DataInputStream(fin));
  168. if (!classfile.getName().equals(qualifiedName))
  169. throw new RuntimeException("cannot find " + qualifiedName + ": "
  170. + classfile.getName() + " found in "
  171. + qualifiedName.replace('.', '/') + ".class");
  172. return classfile;
  173. }
  174. catch (NotFoundException e) {
  175. throw new RuntimeException(e.toString());
  176. }
  177. catch (IOException e) {
  178. throw new RuntimeException(e.toString());
  179. }
  180. finally {
  181. if (fin != null)
  182. try {
  183. fin.close();
  184. }
  185. catch (IOException e) {}
  186. }
  187. }
  188. /* Inherited from CtClass. Called by get() in ClassPool.
  189. *
  190. * @see javassist.CtClass#incGetCounter()
  191. */
  192. void incGetCounter() { ++getCounter; }
  193. /**
  194. * Releases the class files and cached CtBehaviors
  195. * of the CtClasses that have not been recently used
  196. * if they are unmodified.
  197. */
  198. private void releaseClassFiles() {
  199. Enumeration e = classPool.classes.elements();
  200. while (e.hasMoreElements()) {
  201. Object obj = e.nextElement();
  202. if (obj instanceof CtClassType) {
  203. CtClassType cct = (CtClassType)obj;
  204. if (cct.getCounter < 2 && !cct.isModified()) {
  205. cct.eraseCache();
  206. cct.classfile = null;
  207. }
  208. cct.getCounter = 0;
  209. }
  210. }
  211. }
  212. public ClassPool getClassPool() { return classPool; }
  213. void setClassPool(ClassPool cp) { classPool = cp; }
  214. public URL getURL() throws NotFoundException {
  215. URL url = classPool.find(getName());
  216. if (url == null)
  217. throw new NotFoundException(getName());
  218. else
  219. return url;
  220. }
  221. public boolean isModified() { return wasChanged; }
  222. public boolean isFrozen() { return wasFrozen; }
  223. void freeze() { wasFrozen = true; }
  224. void checkModify() throws RuntimeException {
  225. if (isFrozen()) {
  226. String msg = getName() + " class is frozen";
  227. if (wasPruned)
  228. msg += " and pruned";
  229. throw new RuntimeException(msg);
  230. }
  231. wasChanged = true;
  232. }
  233. public void defrost() {
  234. checkPruned("defrost");
  235. wasFrozen = false;
  236. }
  237. public boolean subtypeOf(CtClass clazz) throws NotFoundException {
  238. int i;
  239. String cname = clazz.getName();
  240. if (this == clazz || getName().equals(cname))
  241. return true;
  242. ClassFile file = getClassFile2();
  243. String supername = file.getSuperclass();
  244. if (supername != null && supername.equals(cname))
  245. return true;
  246. String[] ifs = file.getInterfaces();
  247. int num = ifs.length;
  248. for (i = 0; i < num; ++i)
  249. if (ifs[i].equals(cname))
  250. return true;
  251. if (supername != null && classPool.get(supername).subtypeOf(clazz))
  252. return true;
  253. for (i = 0; i < num; ++i)
  254. if (classPool.get(ifs[i]).subtypeOf(clazz))
  255. return true;
  256. return false;
  257. }
  258. public void setName(String name) throws RuntimeException {
  259. String oldname = getName();
  260. if (name.equals(oldname))
  261. return;
  262. // check this in advance although classNameChanged() below does.
  263. classPool.checkNotFrozen(name);
  264. ClassFile cf = getClassFile2();
  265. super.setName(name);
  266. cf.setName(name);
  267. eraseCache();
  268. classPool.classNameChanged(oldname, this);
  269. }
  270. public void replaceClassName(ClassMap classnames)
  271. throws RuntimeException
  272. {
  273. String oldClassName = getName();
  274. String newClassName
  275. = (String)classnames.get(Descriptor.toJvmName(oldClassName));
  276. if (newClassName != null) {
  277. newClassName = Descriptor.toJavaName(newClassName);
  278. // check this in advance although classNameChanged() below does.
  279. classPool.checkNotFrozen(newClassName);
  280. }
  281. super.replaceClassName(classnames);
  282. ClassFile cf = getClassFile2();
  283. cf.renameClass(classnames);
  284. eraseCache();
  285. if (newClassName != null) {
  286. super.setName(newClassName);
  287. classPool.classNameChanged(oldClassName, this);
  288. }
  289. }
  290. public void replaceClassName(String oldname, String newname)
  291. throws RuntimeException
  292. {
  293. String thisname = getName();
  294. if (thisname.equals(oldname))
  295. setName(newname);
  296. else {
  297. super.replaceClassName(oldname, newname);
  298. getClassFile2().renameClass(oldname, newname);
  299. eraseCache();
  300. }
  301. }
  302. public boolean isInterface() {
  303. return Modifier.isInterface(getModifiers());
  304. }
  305. public int getModifiers() {
  306. int acc = getClassFile2().getAccessFlags();
  307. acc = AccessFlag.clear(acc, AccessFlag.SUPER);
  308. return AccessFlag.toModifier(acc);
  309. }
  310. public void setModifiers(int mod) {
  311. checkModify();
  312. int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
  313. getClassFile2().setAccessFlags(acc);
  314. }
  315. public Object[] getAnnotations() throws ClassNotFoundException {
  316. ClassFile cf = getClassFile2();
  317. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  318. cf.getAttribute(AnnotationsAttribute.invisibleTag);
  319. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  320. cf.getAttribute(AnnotationsAttribute.visibleTag);
  321. return toAnnotationType(getClassPool(), ainfo, ainfo2);
  322. }
  323. static Object[] toAnnotationType(ClassPool cp, AnnotationsAttribute a1,
  324. AnnotationsAttribute a2) throws ClassNotFoundException {
  325. Annotation[] anno1, anno2;
  326. int size1, size2;
  327. if (a1 == null) {
  328. anno1 = null;
  329. size1 = 0;
  330. }
  331. else {
  332. anno1 = a1.getAnnotations();
  333. size1 = anno1.length;
  334. }
  335. if (a2 == null) {
  336. anno2 = null;
  337. size2 = 0;
  338. }
  339. else {
  340. anno2 = a2.getAnnotations();
  341. size2 = anno2.length;
  342. }
  343. Object[] result = new Object[size1 + size2];
  344. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  345. for (int i = 0; i < size1; i++)
  346. result[i] = anno1[i].toAnnotationType(cl, cp);
  347. for (int j = 0; j < size2; j++)
  348. result[j + size1] = anno2[j].toAnnotationType(cl, cp);
  349. return result;
  350. }
  351. public boolean subclassOf(CtClass superclass) {
  352. if (superclass == null)
  353. return false;
  354. String superName = superclass.getName();
  355. CtClass curr = this;
  356. try {
  357. while (curr != null) {
  358. if (curr.getName().equals(superName))
  359. return true;
  360. curr = curr.getSuperclass();
  361. }
  362. }
  363. catch (Exception ignored) {}
  364. return false;
  365. }
  366. public CtClass getSuperclass() throws NotFoundException {
  367. String supername = getClassFile2().getSuperclass();
  368. if (supername == null)
  369. return null;
  370. else
  371. return classPool.get(supername);
  372. }
  373. public void setSuperclass(CtClass clazz) throws CannotCompileException {
  374. checkModify();
  375. if (isInterface())
  376. addInterface(clazz);
  377. else
  378. getClassFile2().setSuperclass(clazz.getName());
  379. }
  380. public CtClass[] getInterfaces() throws NotFoundException {
  381. String[] ifs = getClassFile2().getInterfaces();
  382. int num = ifs.length;
  383. CtClass[] ifc = new CtClass[num];
  384. for (int i = 0; i < num; ++i)
  385. ifc[i] = classPool.get(ifs[i]);
  386. return ifc;
  387. }
  388. public void setInterfaces(CtClass[] list) {
  389. checkModify();
  390. String[] ifs;
  391. if (list == null)
  392. ifs = new String[0];
  393. else {
  394. int num = list.length;
  395. ifs = new String[num];
  396. for (int i = 0; i < num; ++i)
  397. ifs[i] = list[i].getName();
  398. }
  399. getClassFile2().setInterfaces(ifs);
  400. }
  401. public void addInterface(CtClass anInterface) {
  402. checkModify();
  403. if (anInterface != null)
  404. getClassFile2().addInterface(anInterface.getName());
  405. }
  406. public CtClass getDeclaringClass() throws NotFoundException {
  407. ClassFile cf = getClassFile2();
  408. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  409. InnerClassesAttribute.tag);
  410. if (ica == null)
  411. return null;
  412. String name = getName();
  413. int n = ica.tableLength();
  414. for (int i = 0; i < n; ++i)
  415. if (name.equals(ica.innerClass(i))) {
  416. String outName = ica.outerClass(i);
  417. if (outName != null)
  418. return classPool.get(outName);
  419. else {
  420. // maybe anonymous or local class.
  421. EnclosingMethodAttribute ema
  422. = (EnclosingMethodAttribute)cf.getAttribute(
  423. EnclosingMethodAttribute.tag);
  424. if (ema != null)
  425. return classPool.get(ema.className());
  426. }
  427. }
  428. return null;
  429. }
  430. public CtMethod getEnclosingMethod() throws NotFoundException {
  431. ClassFile cf = getClassFile2();
  432. EnclosingMethodAttribute ema
  433. = (EnclosingMethodAttribute)cf.getAttribute(
  434. EnclosingMethodAttribute.tag);
  435. if (ema != null) {
  436. CtClass enc = classPool.get(ema.className());
  437. return enc.getMethod(ema.methodName(), ema.methodDescriptor());
  438. }
  439. return null;
  440. }
  441. public CtClass makeNestedClass(String name, boolean isStatic) {
  442. if (!isStatic)
  443. throw new RuntimeException(
  444. "sorry, only nested static class is supported");
  445. checkModify();
  446. CtClass c = classPool.makeNestedClass(getName() + "$" + name);
  447. ClassFile cf = getClassFile2();
  448. ClassFile cf2 = c.getClassFile2();
  449. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  450. InnerClassesAttribute.tag);
  451. if (ica == null) {
  452. ica = new InnerClassesAttribute(cf.getConstPool());
  453. cf.addAttribute(ica);
  454. }
  455. ica.append(c.getName(), this.getName(), name,
  456. (cf2.getAccessFlags() & ~AccessFlag.SUPER) | AccessFlag.STATIC);
  457. cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
  458. return c;
  459. }
  460. public CtField[] getFields() {
  461. ArrayList alist = new ArrayList();
  462. getFields(alist, this);
  463. return (CtField[])alist.toArray(new CtField[alist.size()]);
  464. }
  465. private static void getFields(ArrayList alist, CtClass cc) {
  466. int i, num;
  467. if (cc == null)
  468. return;
  469. try {
  470. getFields(alist, cc.getSuperclass());
  471. }
  472. catch (NotFoundException e) {}
  473. try {
  474. CtClass[] ifs = cc.getInterfaces();
  475. num = ifs.length;
  476. for (i = 0; i < num; ++i)
  477. getFields(alist, ifs[i]);
  478. }
  479. catch (NotFoundException e) {}
  480. CtMember cf = ((CtClassType)cc).getFieldsCache();
  481. while (cf != null) {
  482. if (!Modifier.isPrivate(cf.getModifiers()))
  483. alist.add(cf);
  484. cf = cf.next;
  485. }
  486. }
  487. public CtField getField(String name) throws NotFoundException {
  488. CtField f = getField2(name);
  489. if (f == null)
  490. throw new NotFoundException("field: " + name + " in " + getName());
  491. else
  492. return f;
  493. }
  494. CtField getField2(String name) {
  495. CtField df = getDeclaredField2(name);
  496. if (df != null)
  497. return df;
  498. try {
  499. CtClass[] ifs = getInterfaces();
  500. int num = ifs.length;
  501. for (int i = 0; i < num; ++i) {
  502. CtField f = ifs[i].getField2(name);
  503. if (f != null)
  504. return f;
  505. }
  506. CtClass s = getSuperclass();
  507. if (s != null)
  508. return s.getField2(name);
  509. }
  510. catch (NotFoundException e) {}
  511. return null;
  512. }
  513. public CtField[] getDeclaredFields() {
  514. CtMember cf = getFieldsCache();
  515. int num = CtField.count(cf);
  516. CtField[] cfs = new CtField[num];
  517. int i = 0;
  518. while (cf != null) {
  519. cfs[i++] = (CtField)cf;
  520. cf = cf.next;
  521. }
  522. return cfs;
  523. }
  524. protected CtMember getFieldsCache() {
  525. if (fieldsCache == null) {
  526. List list = getClassFile2().getFields();
  527. int n = list.size();
  528. CtMember allFields = null;
  529. CtField tail = null;
  530. for (int i = 0; i < n; ++i) {
  531. FieldInfo finfo = (FieldInfo)list.get(i);
  532. CtField newTail = new CtField(finfo, this);
  533. allFields = CtMember.append(allFields, tail, newTail);
  534. tail = newTail;
  535. }
  536. fieldsCache = allFields;
  537. }
  538. return fieldsCache;
  539. }
  540. public CtField getDeclaredField(String name) throws NotFoundException {
  541. CtField f = getDeclaredField2(name);
  542. if (f == null)
  543. throw new NotFoundException("field: " + name + " in " + getName());
  544. else
  545. return f;
  546. }
  547. private CtField getDeclaredField2(String name) {
  548. CtMember cf = getFieldsCache();
  549. while (cf != null) {
  550. if (cf.getName().equals(name))
  551. return (CtField)cf;
  552. cf = cf.next;
  553. }
  554. return null;
  555. }
  556. public CtBehavior[] getDeclaredBehaviors() {
  557. CtMember cc = getConstructorsCache();
  558. CtMember cm = getMethodsCache();
  559. int num = CtMember.count(cm) + CtMember.count(cc);
  560. CtBehavior[] cb = new CtBehavior[num];
  561. int i = 0;
  562. while (cc != null) {
  563. cb[i++] = (CtBehavior)cc;
  564. cc = cc.next;
  565. }
  566. while (cm != null) {
  567. cb[i++] = (CtBehavior)cm;
  568. cm = cm.next;
  569. }
  570. return cb;
  571. }
  572. public CtConstructor[] getConstructors() {
  573. CtConstructor[] cons = getDeclaredConstructors();
  574. if (cons.length == 0)
  575. return cons;
  576. int n = 0;
  577. int i = cons.length;
  578. while (--i >= 0)
  579. if (!Modifier.isPrivate(cons[i].getModifiers()))
  580. ++n;
  581. CtConstructor[] result = new CtConstructor[n];
  582. n = 0;
  583. i = cons.length;
  584. while (--i >= 0) {
  585. CtConstructor c = cons[i];
  586. if (!Modifier.isPrivate(c.getModifiers()))
  587. result[n++] = c;
  588. }
  589. return result;
  590. }
  591. public CtConstructor getConstructor(String desc)
  592. throws NotFoundException
  593. {
  594. CtConstructor cc = (CtConstructor)getConstructorsCache();
  595. while (cc != null) {
  596. if (cc.getMethodInfo2().getDescriptor().equals(desc))
  597. return cc;
  598. cc = (CtConstructor)cc.next;
  599. }
  600. return super.getConstructor(desc);
  601. }
  602. public CtConstructor[] getDeclaredConstructors() {
  603. CtMember cc = getConstructorsCache();
  604. int num = CtMember.count(cc);
  605. CtConstructor[] ccs = new CtConstructor[num];
  606. int i = 0;
  607. while (cc != null) {
  608. ccs[i++] = (CtConstructor)cc;
  609. cc = cc.next;
  610. }
  611. return ccs;
  612. }
  613. protected CtMember getConstructorsCache() {
  614. if (constructorsCache == null) {
  615. List list = getClassFile2().getMethods();
  616. int n = list.size();
  617. CtMember allConstructors = null;
  618. CtConstructor tail = null;
  619. for (int i = 0; i < n; ++i) {
  620. MethodInfo minfo = (MethodInfo)list.get(i);
  621. if (minfo.isConstructor()) {
  622. CtConstructor newTail = new CtConstructor(minfo, this);
  623. allConstructors = CtMember.append(allConstructors, tail, newTail);
  624. tail = newTail;
  625. }
  626. }
  627. constructorsCache = allConstructors;
  628. }
  629. return constructorsCache;
  630. }
  631. public CtConstructor getClassInitializer() {
  632. if (classInitializerCache == null) {
  633. MethodInfo minfo = getClassFile2().getStaticInitializer();
  634. if (minfo != null)
  635. classInitializerCache = new CtConstructor(minfo, this);
  636. }
  637. return classInitializerCache;
  638. }
  639. public CtMethod[] getMethods() {
  640. HashMap h = new HashMap();
  641. getMethods0(h, this);
  642. return (CtMethod[])h.values().toArray(new CtMethod[h.size()]);
  643. }
  644. private static void getMethods0(HashMap h, CtClass cc) {
  645. try {
  646. CtClass[] ifs = cc.getInterfaces();
  647. int size = ifs.length;
  648. for (int i = 0; i < size; ++i)
  649. getMethods0(h, ifs[i]);
  650. }
  651. catch (NotFoundException e) {}
  652. try {
  653. CtClass s = cc.getSuperclass();
  654. if (s != null)
  655. getMethods0(h, s);
  656. }
  657. catch (NotFoundException e) {}
  658. if (cc instanceof CtClassType) {
  659. CtMember cm = ((CtClassType)cc).getMethodsCache();
  660. while (cm != null) {
  661. if (!Modifier.isPrivate(cm.getModifiers()))
  662. h.put(((CtMethod)cm).getStringRep(), cm);
  663. cm = cm.next;
  664. }
  665. }
  666. }
  667. public CtMethod getMethod(String name, String desc)
  668. throws NotFoundException
  669. {
  670. CtMethod m = getMethod0(this, name, desc);
  671. if (m != null)
  672. return m;
  673. else
  674. throw new NotFoundException(name + "(..) is not found in "
  675. + getName());
  676. }
  677. private static CtMethod getMethod0(CtClass cc,
  678. String name, String desc) {
  679. if (cc instanceof CtClassType) {
  680. CtMethod cm = (CtMethod)((CtClassType)cc).getMethodsCache();
  681. while (cm != null) {
  682. if (cm.getName().equals(name)
  683. && cm.getMethodInfo2().getDescriptor().equals(desc))
  684. return cm;
  685. cm = (CtMethod)cm.next;
  686. }
  687. }
  688. try {
  689. CtClass s = cc.getSuperclass();
  690. if (s != null) {
  691. CtMethod m = getMethod0(s, name, desc);
  692. if (m != null)
  693. return m;
  694. }
  695. }
  696. catch (NotFoundException e) {}
  697. try {
  698. CtClass[] ifs = cc.getInterfaces();
  699. int size = ifs.length;
  700. for (int i = 0; i < size; ++i) {
  701. CtMethod m = getMethod0(ifs[i], name, desc);
  702. if (m != null)
  703. return m;
  704. }
  705. }
  706. catch (NotFoundException e) {}
  707. return null;
  708. }
  709. public CtMethod[] getDeclaredMethods() {
  710. CtMember cm = getMethodsCache();
  711. int num = CtMember.count(cm);
  712. CtMethod[] cms = new CtMethod[num];
  713. int i = 0;
  714. while (cm != null) {
  715. cms[i++] = (CtMethod)cm;
  716. cm = cm.next;
  717. }
  718. return cms;
  719. }
  720. public CtMethod getDeclaredMethod(String name) throws NotFoundException {
  721. CtMember m = getMethodsCache();
  722. while (m != null) {
  723. if (m.getName().equals(name))
  724. return (CtMethod)m;
  725. m = m.next;
  726. }
  727. throw new NotFoundException(name + "(..) is not found in "
  728. + getName());
  729. }
  730. public CtMethod getDeclaredMethod(String name, CtClass[] params)
  731. throws NotFoundException
  732. {
  733. String desc = Descriptor.ofParameters(params);
  734. CtMethod m = (CtMethod)getMethodsCache();
  735. while (m != null) {
  736. if (m.getName().equals(name)
  737. && m.getMethodInfo2().getDescriptor().startsWith(desc))
  738. return m;
  739. m = (CtMethod)m.next;
  740. }
  741. throw new NotFoundException(name + "(..) is not found in "
  742. + getName());
  743. }
  744. protected CtMember getMethodsCache() {
  745. if (methodsCache == null) {
  746. List list = getClassFile2().getMethods();
  747. int n = list.size();
  748. CtMember allMethods = null;
  749. CtMethod tail = null;
  750. for (int i = 0; i < n; ++i) {
  751. MethodInfo minfo = (MethodInfo)list.get(i);
  752. if (minfo.isMethod()) {
  753. CtMethod newTail = new CtMethod(minfo, this);
  754. allMethods = CtMember.append(allMethods, tail, newTail);
  755. tail = newTail;
  756. }
  757. }
  758. methodsCache = allMethods;
  759. }
  760. return methodsCache;
  761. }
  762. public void addField(CtField f, String init)
  763. throws CannotCompileException
  764. {
  765. addField(f, CtField.Initializer.byExpr(init));
  766. }
  767. public void addField(CtField f, CtField.Initializer init)
  768. throws CannotCompileException
  769. {
  770. checkModify();
  771. if (f.getDeclaringClass() != this)
  772. throw new CannotCompileException("cannot add");
  773. if (init == null)
  774. init = f.getInit();
  775. if (init != null) {
  776. int mod = f.getModifiers();
  777. if (Modifier.isStatic(mod) && Modifier.isFinal(mod))
  778. try {
  779. ConstPool cp = getClassFile2().getConstPool();
  780. int index = init.getConstantValue(cp, f.getType());
  781. if (index != 0) {
  782. f.getFieldInfo2().addAttribute(new ConstantAttribute(cp, index));
  783. init = null;
  784. }
  785. }
  786. catch (NotFoundException e) {}
  787. }
  788. getFieldsCache();
  789. fieldsCache = CtField.append(fieldsCache, f);
  790. getClassFile2().addField(f.getFieldInfo2());
  791. if (init != null) {
  792. FieldInitLink fil = new FieldInitLink(f, init);
  793. FieldInitLink link = fieldInitializers;
  794. if (link == null)
  795. fieldInitializers = fil;
  796. else {
  797. while (link.next != null)
  798. link = link.next;
  799. link.next = fil;
  800. }
  801. }
  802. }
  803. public void removeField(CtField f) throws NotFoundException {
  804. checkModify();
  805. FieldInfo fi = f.getFieldInfo2();
  806. ClassFile cf = getClassFile2();
  807. if (cf.getFields().remove(fi)) {
  808. fieldsCache = CtMember.remove(fieldsCache, f);
  809. memberRemoved = true;
  810. }
  811. else
  812. throw new NotFoundException(f.toString());
  813. }
  814. public CtConstructor makeClassInitializer()
  815. throws CannotCompileException
  816. {
  817. CtConstructor clinit = getClassInitializer();
  818. if (clinit != null)
  819. return clinit;
  820. checkModify();
  821. ClassFile cf = getClassFile2();
  822. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  823. modifyClassConstructor(cf, code, 0, 0);
  824. return getClassInitializer();
  825. }
  826. public void addConstructor(CtConstructor c)
  827. throws CannotCompileException
  828. {
  829. checkModify();
  830. if (c.getDeclaringClass() != this)
  831. throw new CannotCompileException("cannot add");
  832. getConstructorsCache();
  833. constructorsCache = (CtConstructor)CtMember.append(constructorsCache, c);
  834. getClassFile2().addMethod(c.getMethodInfo2());
  835. }
  836. public void removeConstructor(CtConstructor m) throws NotFoundException {
  837. checkModify();
  838. MethodInfo mi = m.getMethodInfo2();
  839. ClassFile cf = getClassFile2();
  840. if (cf.getMethods().remove(mi)) {
  841. constructorsCache = CtMember.remove(constructorsCache, m);
  842. memberRemoved = true;
  843. }
  844. else
  845. throw new NotFoundException(m.toString());
  846. }
  847. public void addMethod(CtMethod m) throws CannotCompileException {
  848. checkModify();
  849. if (m.getDeclaringClass() != this)
  850. throw new CannotCompileException("cannot add");
  851. getMethodsCache();
  852. methodsCache = CtMember.append(methodsCache, m);
  853. getClassFile2().addMethod(m.getMethodInfo2());
  854. if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
  855. setModifiers(getModifiers() | Modifier.ABSTRACT);
  856. }
  857. public void removeMethod(CtMethod m) throws NotFoundException {
  858. checkModify();
  859. MethodInfo mi = m.getMethodInfo2();
  860. ClassFile cf = getClassFile2();
  861. if (cf.getMethods().remove(mi)) {
  862. methodsCache = CtMember.remove(methodsCache, m);
  863. memberRemoved = true;
  864. }
  865. else
  866. throw new NotFoundException(m.toString());
  867. }
  868. public byte[] getAttribute(String name) {
  869. AttributeInfo ai = getClassFile2().getAttribute(name);
  870. if (ai == null)
  871. return null;
  872. else
  873. return ai.get();
  874. }
  875. public void setAttribute(String name, byte[] data) {
  876. checkModify();
  877. ClassFile cf = getClassFile2();
  878. cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
  879. }
  880. public void instrument(CodeConverter converter)
  881. throws CannotCompileException
  882. {
  883. checkModify();
  884. ClassFile cf = getClassFile2();
  885. ConstPool cp = cf.getConstPool();
  886. List list = cf.getMethods();
  887. int n = list.size();
  888. for (int i = 0; i < n; ++i) {
  889. MethodInfo minfo = (MethodInfo)list.get(i);
  890. converter.doit(this, minfo, cp);
  891. }
  892. }
  893. public void instrument(ExprEditor editor)
  894. throws CannotCompileException
  895. {
  896. checkModify();
  897. ClassFile cf = getClassFile2();
  898. List list = cf.getMethods();
  899. int n = list.size();
  900. for (int i = 0; i < n; ++i) {
  901. MethodInfo minfo = (MethodInfo)list.get(i);
  902. editor.doit(this, minfo);
  903. }
  904. }
  905. /**
  906. * @see javassist.CtClass#prune()
  907. * @see javassist.CtClass#stopPruning(boolean)
  908. */
  909. public void prune() {
  910. if (wasPruned)
  911. return;
  912. wasPruned = wasFrozen = true;
  913. getClassFile2().prune();
  914. }
  915. public void toBytecode(DataOutputStream out)
  916. throws CannotCompileException, IOException
  917. {
  918. try {
  919. if (isModified()) {
  920. checkPruned("toBytecode");
  921. ClassFile cf = getClassFile2();
  922. if (memberRemoved) {
  923. cf.compact();
  924. memberRemoved = false;
  925. }
  926. modifyClassConstructor(cf);
  927. modifyConstructors(cf);
  928. cf.write(out);
  929. out.flush();
  930. fieldInitializers = null;
  931. if (doPruning) {
  932. // to save memory
  933. cf.prune();
  934. wasPruned = true;
  935. }
  936. }
  937. else {
  938. classPool.writeClassfile(getName(), out);
  939. // to save memory
  940. eraseCache();
  941. classfile = null;
  942. }
  943. wasFrozen = true;
  944. }
  945. catch (NotFoundException e) {
  946. throw new CannotCompileException(e);
  947. }
  948. catch (IOException e) {
  949. throw new CannotCompileException(e);
  950. }
  951. }
  952. /* See also checkModified()
  953. */
  954. private void checkPruned(String method) {
  955. if (wasPruned)
  956. throw new RuntimeException(method + "(): " + getName()
  957. + " was pruned.");
  958. }
  959. public boolean stopPruning(boolean stop) {
  960. boolean prev = !doPruning;
  961. doPruning = !stop;
  962. return prev;
  963. }
  964. private void modifyClassConstructor(ClassFile cf)
  965. throws CannotCompileException, NotFoundException
  966. {
  967. if (fieldInitializers == null)
  968. return;
  969. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  970. Javac jv = new Javac(code, this);
  971. int stacksize = 0;
  972. boolean doInit = false;
  973. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  974. CtField f = fi.field;
  975. if (Modifier.isStatic(f.getModifiers())) {
  976. doInit = true;
  977. int s = fi.init.compileIfStatic(f.getType(), f.getName(),
  978. code, jv);
  979. if (stacksize < s)
  980. stacksize = s;
  981. }
  982. }
  983. if (doInit) // need an initializer for static fileds.
  984. modifyClassConstructor(cf, code, stacksize, 0);
  985. }
  986. private void modifyClassConstructor(ClassFile cf, Bytecode code,
  987. int stacksize, int localsize)
  988. throws CannotCompileException
  989. {
  990. MethodInfo m = cf.getStaticInitializer();
  991. if (m == null) {
  992. code.add(Bytecode.RETURN);
  993. code.setMaxStack(stacksize);
  994. code.setMaxLocals(localsize);
  995. m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
  996. m.setAccessFlags(AccessFlag.STATIC);
  997. m.setCodeAttribute(code.toCodeAttribute());
  998. cf.addMethod(m);
  999. }
  1000. else {
  1001. CodeAttribute codeAttr = m.getCodeAttribute();
  1002. if (codeAttr == null)
  1003. throw new CannotCompileException("empty <clinit>");
  1004. try {
  1005. CodeIterator it = codeAttr.iterator();
  1006. int pos = it.insertEx(code.get());
  1007. it.insert(code.getExceptionTable(), pos);
  1008. int maxstack = codeAttr.getMaxStack();
  1009. if (maxstack < stacksize)
  1010. codeAttr.setMaxStack(stacksize);
  1011. int maxlocals = codeAttr.getMaxLocals();
  1012. if (maxlocals < localsize)
  1013. codeAttr.setMaxLocals(localsize);
  1014. }
  1015. catch (BadBytecode e) {
  1016. throw new CannotCompileException(e);
  1017. }
  1018. }
  1019. }
  1020. private void modifyConstructors(ClassFile cf)
  1021. throws CannotCompileException, NotFoundException
  1022. {
  1023. if (fieldInitializers == null)
  1024. return;
  1025. ConstPool cp = cf.getConstPool();
  1026. List list = cf.getMethods();
  1027. int n = list.size();
  1028. for (int i = 0; i < n; ++i) {
  1029. MethodInfo minfo = (MethodInfo)list.get(i);
  1030. if (minfo.isConstructor()) {
  1031. CodeAttribute codeAttr = minfo.getCodeAttribute();
  1032. if (codeAttr != null)
  1033. try {
  1034. Bytecode init = new Bytecode(cp, 0,
  1035. codeAttr.getMaxLocals());
  1036. CtClass[] params
  1037. = Descriptor.getParameterTypes(
  1038. minfo.getDescriptor(),
  1039. classPool);
  1040. int stacksize = makeFieldInitializer(init, params);
  1041. insertAuxInitializer(codeAttr, init, stacksize);
  1042. }
  1043. catch (BadBytecode e) {
  1044. throw new CannotCompileException(e);
  1045. }
  1046. }
  1047. }
  1048. }
  1049. private static void insertAuxInitializer(CodeAttribute codeAttr,
  1050. Bytecode initializer,
  1051. int stacksize)
  1052. throws BadBytecode
  1053. {
  1054. CodeIterator it = codeAttr.iterator();
  1055. int index = it.skipSuperConstructor();
  1056. if (index < 0) {
  1057. index = it.skipThisConstructor();
  1058. if (index >= 0)
  1059. return; // this() is called.
  1060. // Neither this() or super() is called.
  1061. }
  1062. int pos = it.insertEx(initializer.get());
  1063. it.insert(initializer.getExceptionTable(), pos);
  1064. int maxstack = codeAttr.getMaxStack();
  1065. if (maxstack < stacksize)
  1066. codeAttr.setMaxStack(stacksize);
  1067. }
  1068. private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
  1069. throws CannotCompileException, NotFoundException
  1070. {
  1071. int stacksize = 0;
  1072. Javac jv = new Javac(code, this);
  1073. try {
  1074. jv.recordParams(parameters, false);
  1075. }
  1076. catch (CompileError e) {
  1077. throw new CannotCompileException(e);
  1078. }
  1079. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  1080. CtField f = fi.field;
  1081. if (!Modifier.isStatic(f.getModifiers())) {
  1082. int s = fi.init.compile(f.getType(), f.getName(), code,
  1083. parameters, jv);
  1084. if (stacksize < s)
  1085. stacksize = s;
  1086. }
  1087. }
  1088. return stacksize;
  1089. }
  1090. // Methods used by CtNewWrappedMethod
  1091. Hashtable getHiddenMethods() {
  1092. if (hiddenMethods == null)
  1093. hiddenMethods = new Hashtable();
  1094. return hiddenMethods;
  1095. }
  1096. int getUniqueNumber() { return uniqueNumberSeed++; }
  1097. public String makeUniqueName(String prefix) {
  1098. HashMap table = new HashMap();
  1099. makeMemberList(table);
  1100. Set keys = table.keySet();
  1101. String[] methods = new String[keys.size()];
  1102. keys.toArray(methods);
  1103. if (notFindInArray(prefix, methods))
  1104. return prefix;
  1105. int i = 100;
  1106. String name;
  1107. do {
  1108. if (i > 999)
  1109. throw new RuntimeException("too many unique name");
  1110. name = prefix + i++;
  1111. } while (!notFindInArray(name, methods));
  1112. return name;
  1113. }
  1114. private static boolean notFindInArray(String prefix, String[] values) {
  1115. int len = values.length;
  1116. for (int i = 0; i < len; i++)
  1117. if (values[i].startsWith(prefix))
  1118. return false;
  1119. return true;
  1120. }
  1121. private void makeMemberList(HashMap table) {
  1122. int mod = getModifiers();
  1123. if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
  1124. try {
  1125. CtClass[] ifs = getInterfaces();
  1126. int size = ifs.length;
  1127. for (int i = 0; i < size; i++) {
  1128. CtClass ic =ifs[i];
  1129. if (ic != null && ic instanceof CtClassType)
  1130. ((CtClassType)ic).makeMemberList(table);
  1131. }
  1132. }
  1133. catch (NotFoundException e) {}
  1134. try {
  1135. CtClass s = getSuperclass();
  1136. if (s != null && s instanceof CtClassType)
  1137. ((CtClassType)s).makeMemberList(table);
  1138. }
  1139. catch (NotFoundException e) {}
  1140. List list = getClassFile2().getMethods();
  1141. int n = list.size();
  1142. for (int i = 0; i < n; i++) {
  1143. MethodInfo minfo = (MethodInfo)list.get(i);
  1144. table.put(minfo.getName(), this);
  1145. }
  1146. list = getClassFile2().getFields();
  1147. n = list.size();
  1148. for (int i = 0; i < n; i++) {
  1149. FieldInfo finfo = (FieldInfo)list.get(i);
  1150. table.put(finfo.getName(), this);
  1151. }
  1152. }
  1153. }
  1154. class FieldInitLink {
  1155. FieldInitLink next;
  1156. CtField field;
  1157. CtField.Initializer init;
  1158. FieldInitLink(CtField f, CtField.Initializer i) {
  1159. next = null;
  1160. field = f;
  1161. init = i;
  1162. }
  1163. }