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

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