Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

CtClassType.java 29KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 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 javassist.bytecode.*;
  17. import javassist.compiler.Javac;
  18. import javassist.compiler.CompileError;
  19. import javassist.compiler.AccessorMaker;
  20. import javassist.expr.ExprEditor;
  21. import java.io.InputStream;
  22. import java.io.BufferedInputStream;
  23. import java.io.DataInputStream;
  24. import java.io.DataOutputStream;
  25. import java.io.IOException;
  26. import java.net.URL;
  27. import java.util.ArrayList;
  28. import java.util.HashMap;
  29. import java.util.Hashtable;
  30. import java.util.List;
  31. /**
  32. * Class types.
  33. */
  34. class CtClassType extends CtClass {
  35. ClassPool classPool;
  36. boolean wasChanged;
  37. boolean wasFrozen;
  38. ClassFile classfile;
  39. private CtField fieldsCache;
  40. private CtConstructor constructorsCache;
  41. private CtConstructor classInitializerCache;
  42. private CtMethod methodsCache;
  43. private AccessorMaker accessors;
  44. private FieldInitLink fieldInitializers;
  45. private Hashtable hiddenMethods; // must be synchronous
  46. private int uniqueNumberSeed;
  47. CtClassType(String name, ClassPool cp) {
  48. super(name);
  49. classPool = cp;
  50. wasChanged = wasFrozen = false;
  51. classfile = null;
  52. accessors = null;
  53. fieldInitializers = null;
  54. hiddenMethods = null;
  55. uniqueNumberSeed = 0;
  56. eraseCache();
  57. }
  58. CtClassType(InputStream ins, ClassPool cp) throws IOException {
  59. this((String)null, cp);
  60. classfile = new ClassFile(new DataInputStream(ins));
  61. qualifiedName = classfile.getName();
  62. }
  63. protected void extendToString(StringBuffer buffer) {
  64. if (wasChanged)
  65. buffer.append(" changed");
  66. if (wasFrozen)
  67. buffer.append(" frozen");
  68. CtField field = getFieldsCache();
  69. buffer.append(" fields=");
  70. while (field != null) {
  71. buffer.append(field);
  72. buffer.append(", ");
  73. field = field.next;
  74. }
  75. CtConstructor c = getConstructorsCache();
  76. buffer.append(" constructors=");
  77. while (c != null) {
  78. buffer.append(c);
  79. buffer.append(", ");
  80. c = c.next;
  81. }
  82. CtMethod m = getMethodsCache();
  83. buffer.append(" methods=");
  84. while (m != null) {
  85. buffer.append(m);
  86. buffer.append(", ");
  87. m = m.next;
  88. }
  89. }
  90. protected void eraseCache() {
  91. fieldsCache = null;
  92. constructorsCache = null;
  93. classInitializerCache = null;
  94. methodsCache = null;
  95. }
  96. public AccessorMaker getAccessorMaker() {
  97. if (accessors == null)
  98. accessors = new AccessorMaker(this);
  99. return accessors;
  100. }
  101. public ClassFile getClassFile2() {
  102. if (classfile != null)
  103. return classfile;
  104. InputStream fin = null;
  105. try {
  106. fin = classPool.openClassfile(getName());
  107. if (fin == null)
  108. throw new NotFoundException(getName());
  109. fin = new BufferedInputStream(fin);
  110. classfile = new ClassFile(new DataInputStream(fin));
  111. return classfile;
  112. }
  113. catch (NotFoundException e) {
  114. throw new RuntimeException(e.toString());
  115. }
  116. catch (IOException e) {
  117. throw new RuntimeException(e.toString());
  118. }
  119. finally {
  120. if (fin != null)
  121. try {
  122. fin.close();
  123. }
  124. catch (IOException e) {}
  125. }
  126. }
  127. public ClassPool getClassPool() { return classPool; }
  128. void setClassPool(ClassPool cp) { classPool = cp; }
  129. public URL getURL() throws NotFoundException {
  130. URL url = classPool.find(getName());
  131. if (url == null)
  132. throw new NotFoundException(getName());
  133. else
  134. return url;
  135. }
  136. public boolean isModified() { return wasChanged; }
  137. public boolean isFrozen() { return wasFrozen; }
  138. void freeze() { wasFrozen = true; }
  139. void checkModify() throws RuntimeException {
  140. super.checkModify();
  141. wasChanged = true;
  142. }
  143. public void defrost() { wasFrozen = false; }
  144. public boolean subtypeOf(CtClass clazz) throws NotFoundException {
  145. int i;
  146. String cname = clazz.getName();
  147. if (this == clazz || getName().equals(cname))
  148. return true;
  149. ClassFile file = getClassFile2();
  150. String supername = file.getSuperclass();
  151. if (supername != null && supername.equals(cname))
  152. return true;
  153. String[] ifs = file.getInterfaces();
  154. int num = ifs.length;
  155. for (i = 0; i < num; ++i)
  156. if (ifs[i].equals(cname))
  157. return true;
  158. if (supername != null && classPool.get(supername).subtypeOf(clazz))
  159. return true;
  160. for (i = 0; i < num; ++i)
  161. if (classPool.get(ifs[i]).subtypeOf(clazz))
  162. return true;
  163. return false;
  164. }
  165. public void setName(String name) throws RuntimeException {
  166. String oldname = getName();
  167. if (name.equals(oldname))
  168. return;
  169. // check this in advance although classNameChanged() below does.
  170. classPool.checkNotFrozen(name);
  171. ClassFile cf = getClassFile2();
  172. super.setName(name);
  173. cf.setName(name);
  174. eraseCache();
  175. classPool.classNameChanged(oldname, this);
  176. }
  177. public void replaceClassName(ClassMap classnames)
  178. throws RuntimeException
  179. {
  180. String oldClassName = getName();
  181. String newClassName
  182. = (String)classnames.get(Descriptor.toJvmName(oldClassName));
  183. if (newClassName != null) {
  184. newClassName = Descriptor.toJavaName(newClassName);
  185. // check this in advance although classNameChanged() below does.
  186. classPool.checkNotFrozen(newClassName);
  187. }
  188. super.replaceClassName(classnames);
  189. ClassFile cf = getClassFile2();
  190. cf.renameClass(classnames);
  191. eraseCache();
  192. if (newClassName != null) {
  193. super.setName(newClassName);
  194. classPool.classNameChanged(oldClassName, this);
  195. }
  196. }
  197. public void replaceClassName(String oldname, String newname)
  198. throws RuntimeException
  199. {
  200. String thisname = getName();
  201. if (thisname.equals(oldname))
  202. setName(newname);
  203. else {
  204. super.replaceClassName(oldname, newname);
  205. getClassFile2().renameClass(oldname, newname);
  206. eraseCache();
  207. }
  208. }
  209. public boolean isInterface() {
  210. return Modifier.isInterface(getModifiers());
  211. }
  212. public int getModifiers() {
  213. int acc = getClassFile2().getAccessFlags();
  214. acc = AccessFlag.clear(acc, AccessFlag.SUPER);
  215. return AccessFlag.toModifier(acc);
  216. }
  217. public void setModifiers(int mod) {
  218. checkModify();
  219. int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
  220. getClassFile2().setAccessFlags(acc);
  221. }
  222. public boolean subclassOf(CtClass superclass) {
  223. if (superclass == null)
  224. return false;
  225. String superName = superclass.getName();
  226. CtClass curr = this;
  227. try {
  228. while (curr != null) {
  229. if (curr.getName().equals(superName))
  230. return true;
  231. curr = curr.getSuperclass();
  232. }
  233. }
  234. catch (Exception ignored) {}
  235. return false;
  236. }
  237. public CtClass getSuperclass() throws NotFoundException {
  238. String supername = getClassFile2().getSuperclass();
  239. if (supername == null)
  240. return null;
  241. else
  242. return classPool.get(supername);
  243. }
  244. public void setSuperclass(CtClass clazz) throws CannotCompileException {
  245. checkModify();
  246. if (isInterface())
  247. addInterface(clazz);
  248. else
  249. getClassFile2().setSuperclass(clazz.getName());
  250. }
  251. public CtClass[] getInterfaces() throws NotFoundException {
  252. String[] ifs = getClassFile2().getInterfaces();
  253. int num = ifs.length;
  254. CtClass[] ifc = new CtClass[num];
  255. for (int i = 0; i < num; ++i)
  256. ifc[i] = classPool.get(ifs[i]);
  257. return ifc;
  258. }
  259. public void setInterfaces(CtClass[] list) {
  260. checkModify();
  261. String[] ifs;
  262. if (list == null)
  263. ifs = new String[0];
  264. else {
  265. int num = list.length;
  266. ifs = new String[num];
  267. for (int i = 0; i < num; ++i)
  268. ifs[i] = list[i].getName();
  269. }
  270. getClassFile2().setInterfaces(ifs);
  271. }
  272. public void addInterface(CtClass anInterface) {
  273. checkModify();
  274. if (anInterface != null)
  275. getClassFile2().addInterface(anInterface.getName());
  276. }
  277. public CtClass getDeclaringClass() throws NotFoundException {
  278. ClassFile cf = getClassFile2();
  279. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  280. InnerClassesAttribute.tag);
  281. if (ica == null)
  282. return null;
  283. String name = getName();
  284. int n = ica.tableLength();
  285. for (int i = 0; i < n; ++i)
  286. if (name.equals(ica.innerClass(i)))
  287. return classPool.get(ica.outerClass(i));
  288. return null;
  289. }
  290. public CtClass makeNestedClass(String name, boolean isStatic) {
  291. if (!isStatic)
  292. throw new RuntimeException(
  293. "sorry, only nested static class is supported");
  294. checkModify();
  295. CtClass c = classPool.makeNestedClass(getName() + "$" + name);
  296. ClassFile cf = getClassFile2();
  297. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  298. InnerClassesAttribute.tag);
  299. if (ica == null) {
  300. ica = new InnerClassesAttribute(cf.getConstPool());
  301. cf.addAttribute(ica);
  302. }
  303. ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC);
  304. ClassFile cf2 = c.getClassFile2();
  305. cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
  306. return c;
  307. }
  308. public CtField[] getFields() {
  309. ArrayList alist = new ArrayList();
  310. getFields(alist, this);
  311. return (CtField[])alist.toArray(new CtField[alist.size()]);
  312. }
  313. private static void getFields(ArrayList alist, CtClass cc) {
  314. int i, num;
  315. if (cc == null)
  316. return;
  317. try {
  318. getFields(alist, cc.getSuperclass());
  319. }
  320. catch (NotFoundException e) {}
  321. try {
  322. CtClass[] ifs = cc.getInterfaces();
  323. num = ifs.length;
  324. for (i = 0; i < num; ++i)
  325. getFields(alist, ifs[i]);
  326. }
  327. catch (NotFoundException e) {}
  328. CtField cf = ((CtClassType)cc).getFieldsCache();
  329. while (cf != null) {
  330. if (Modifier.isPublic(cf.getModifiers()))
  331. alist.add(cf);
  332. cf = cf.next;
  333. }
  334. }
  335. public CtField getField(String name) throws NotFoundException {
  336. CtField f = getField2(name);
  337. if (f == null)
  338. throw new NotFoundException("field: " + name + " in " + getName());
  339. else
  340. return f;
  341. }
  342. CtField getField2(String name) {
  343. CtField df = getDeclaredField2(name);
  344. if (df != null)
  345. return df;
  346. try {
  347. CtClass[] ifs = getInterfaces();
  348. int num = ifs.length;
  349. for (int i = 0; i < num; ++i) {
  350. CtField f = ifs[i].getField2(name);
  351. if (f != null)
  352. return f;
  353. }
  354. CtClass s = getSuperclass();
  355. if (s != null)
  356. return s.getField2(name);
  357. }
  358. catch (NotFoundException e) {}
  359. return null;
  360. }
  361. public CtField[] getDeclaredFields() {
  362. CtField cf = getFieldsCache();
  363. int num = CtField.count(cf);
  364. CtField[] cfs = new CtField[num];
  365. int i = 0;
  366. while (cf != null) {
  367. cfs[i++] = cf;
  368. cf = cf.next;
  369. }
  370. return cfs;
  371. }
  372. protected CtField getFieldsCache() {
  373. if (fieldsCache == null) {
  374. List list = getClassFile2().getFields();
  375. int n = list.size();
  376. for (int i = 0; i < n; ++i) {
  377. FieldInfo finfo = (FieldInfo)list.get(i);
  378. fieldsCache = CtField.append(fieldsCache,
  379. new CtField(finfo, this));
  380. }
  381. }
  382. return fieldsCache;
  383. }
  384. public CtField getDeclaredField(String name) throws NotFoundException {
  385. CtField f = getDeclaredField2(name);
  386. if (f == null)
  387. throw new NotFoundException("field: " + name + " in " + getName());
  388. else
  389. return f;
  390. }
  391. private CtField getDeclaredField2(String name) {
  392. CtField cf = getFieldsCache();
  393. while (cf != null) {
  394. if (cf.getName().equals(name))
  395. return cf;
  396. cf = cf.next;
  397. }
  398. return null;
  399. }
  400. public CtBehavior[] getDeclaredBehaviors() {
  401. CtConstructor cc = getConstructorsCache();
  402. CtMethod cm = getMethodsCache();
  403. int num = CtMethod.count(cm) + CtConstructor.count(cc);
  404. CtBehavior[] cb = new CtBehavior[num];
  405. int i = 0;
  406. while (cc != null) {
  407. cb[i++] = cc;
  408. cc = cc.next;
  409. }
  410. while (cm != null) {
  411. cb[i++] = cm;
  412. cm = cm.next;
  413. }
  414. return cb;
  415. }
  416. public CtConstructor[] getConstructors() {
  417. CtConstructor[] cons = getDeclaredConstructors();
  418. if (cons.length == 0)
  419. return cons;
  420. int n = 0;
  421. int i = cons.length;
  422. while (--i >= 0)
  423. if (Modifier.isPublic(cons[i].getModifiers()))
  424. ++n;
  425. CtConstructor[] result = new CtConstructor[n];
  426. n = 0;
  427. i = cons.length;
  428. while (--i >= 0) {
  429. CtConstructor c = cons[i];
  430. if (Modifier.isPublic(c.getModifiers()))
  431. result[n++] = c;
  432. }
  433. return result;
  434. }
  435. public CtConstructor getConstructor(String desc)
  436. throws NotFoundException
  437. {
  438. CtConstructor cc = getConstructorsCache();
  439. while (cc != null) {
  440. if (cc.getMethodInfo2().getDescriptor().equals(desc))
  441. return cc;
  442. cc = cc.next;
  443. }
  444. return super.getConstructor(desc);
  445. }
  446. public CtConstructor[] getDeclaredConstructors() {
  447. CtConstructor cc = getConstructorsCache();
  448. int num = CtConstructor.count(cc);
  449. CtConstructor[] ccs = new CtConstructor[num];
  450. int i = 0;
  451. while (cc != null) {
  452. ccs[i++] = cc;
  453. cc = cc.next;
  454. }
  455. return ccs;
  456. }
  457. protected CtConstructor getConstructorsCache() {
  458. if (constructorsCache == null) {
  459. List list = getClassFile2().getMethods();
  460. int n = list.size();
  461. for (int i = 0; i < n; ++i) {
  462. MethodInfo minfo = (MethodInfo)list.get(i);
  463. if (minfo.isConstructor())
  464. constructorsCache
  465. = CtConstructor.append(constructorsCache,
  466. new CtConstructor(minfo, this));
  467. }
  468. }
  469. return constructorsCache;
  470. }
  471. public CtConstructor getClassInitializer() {
  472. if (classInitializerCache == null) {
  473. MethodInfo minfo = getClassFile2().getStaticInitializer();
  474. if (minfo != null)
  475. classInitializerCache = new CtConstructor(minfo, this);
  476. }
  477. return classInitializerCache;
  478. }
  479. public CtMethod[] getMethods() {
  480. HashMap h = new HashMap();
  481. getMethods0(h, this);
  482. return (CtMethod[])h.values().toArray(new CtMethod[0]);
  483. }
  484. private static void getMethods0(HashMap h, CtClass cc) {
  485. try {
  486. CtClass[] ifs = cc.getInterfaces();
  487. int size = ifs.length;
  488. for (int i = 0; i < size; ++i)
  489. getMethods0(h, ifs[i]);
  490. }
  491. catch (NotFoundException e) {}
  492. try {
  493. CtClass s = cc.getSuperclass();
  494. if (s != null)
  495. getMethods0(h, s);
  496. }
  497. catch (NotFoundException e) {}
  498. if (cc instanceof CtClassType) {
  499. CtMethod cm = ((CtClassType)cc).getMethodsCache();
  500. while (cm != null) {
  501. if (Modifier.isPublic(cm.getModifiers()))
  502. h.put(cm, cm);
  503. cm = cm.next;
  504. }
  505. }
  506. }
  507. public CtMethod getMethod(String name, String desc)
  508. throws NotFoundException
  509. {
  510. CtMethod m = getMethod0(this, name, desc);
  511. if (m != null)
  512. return m;
  513. else
  514. throw new NotFoundException(name + "(..) is not found in "
  515. + getName());
  516. }
  517. private static CtMethod getMethod0(CtClass cc,
  518. String name, String desc) {
  519. if (cc instanceof CtClassType) {
  520. CtMethod cm = ((CtClassType)cc).getMethodsCache();
  521. while (cm != null) {
  522. if (cm.getName().equals(name)
  523. && cm.getMethodInfo2().getDescriptor().equals(desc))
  524. return cm;
  525. cm = cm.next;
  526. }
  527. }
  528. try {
  529. CtClass s = cc.getSuperclass();
  530. if (s != null) {
  531. CtMethod m = getMethod0(s, name, desc);
  532. if (m != null)
  533. return m;
  534. }
  535. }
  536. catch (NotFoundException e) {}
  537. try {
  538. CtClass[] ifs = cc.getInterfaces();
  539. int size = ifs.length;
  540. for (int i = 0; i < size; ++i) {
  541. CtMethod m = getMethod0(ifs[i], name, desc);
  542. if (m != null)
  543. return m;
  544. }
  545. }
  546. catch (NotFoundException e) {}
  547. return null;
  548. }
  549. public CtMethod[] getDeclaredMethods() {
  550. CtMethod cm = getMethodsCache();
  551. int num = CtMethod.count(cm);
  552. CtMethod[] cms = new CtMethod[num];
  553. int i = 0;
  554. while (cm != null) {
  555. cms[i++] = cm;
  556. cm = cm.next;
  557. }
  558. return cms;
  559. }
  560. public CtMethod getDeclaredMethod(String name) throws NotFoundException {
  561. CtMethod m = getMethodsCache();
  562. while (m != null) {
  563. if (m.getName().equals(name))
  564. return m;
  565. m = m.next;
  566. }
  567. throw new NotFoundException(name + "(..) is not found in "
  568. + getName());
  569. }
  570. public CtMethod getDeclaredMethod(String name, CtClass[] params)
  571. throws NotFoundException
  572. {
  573. String desc = Descriptor.ofParameters(params);
  574. CtMethod m = getMethodsCache();
  575. while (m != null) {
  576. if (m.getName().equals(name)
  577. && m.getMethodInfo2().getDescriptor().startsWith(desc))
  578. return m;
  579. m = m.next;
  580. }
  581. throw new NotFoundException(name + "(..) is not found in "
  582. + getName());
  583. }
  584. protected CtMethod getMethodsCache() {
  585. if (methodsCache == null) {
  586. List list = getClassFile2().getMethods();
  587. int n = list.size();
  588. for (int i = 0; i < n; ++i) {
  589. MethodInfo minfo = (MethodInfo)list.get(i);
  590. if (minfo.isMethod())
  591. methodsCache = CtMethod.append(methodsCache,
  592. new CtMethod(minfo, this));
  593. }
  594. }
  595. return methodsCache;
  596. }
  597. public void addField(CtField f, String init)
  598. throws CannotCompileException
  599. {
  600. addField(f, CtField.Initializer.byExpr(init));
  601. }
  602. public void addField(CtField f, CtField.Initializer init)
  603. throws CannotCompileException
  604. {
  605. checkModify();
  606. if (f.getDeclaringClass() != this)
  607. throw new CannotCompileException("cannot add");
  608. if (init == null)
  609. init = f.getInit();
  610. getFieldsCache();
  611. fieldsCache = CtField.append(fieldsCache, f);
  612. getClassFile2().addField(f.getFieldInfo2());
  613. if (init != null) {
  614. FieldInitLink fil = new FieldInitLink(f, init);
  615. FieldInitLink link = fieldInitializers;
  616. if (link == null)
  617. fieldInitializers = fil;
  618. else {
  619. while (link.next != null)
  620. link = link.next;
  621. link.next = fil;
  622. }
  623. }
  624. }
  625. public CtConstructor makeClassInitializer()
  626. throws CannotCompileException
  627. {
  628. CtConstructor clinit = getClassInitializer();
  629. if (clinit != null)
  630. return clinit;
  631. checkModify();
  632. ClassFile cf = getClassFile2();
  633. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  634. modifyClassConstructor(cf, code, 0, 0);
  635. return getClassInitializer();
  636. }
  637. public void addConstructor(CtConstructor c)
  638. throws CannotCompileException
  639. {
  640. checkModify();
  641. if (c.getDeclaringClass() != this)
  642. throw new CannotCompileException("cannot add");
  643. getConstructorsCache();
  644. constructorsCache = CtConstructor.append(constructorsCache, c);
  645. getClassFile2().addMethod(c.getMethodInfo2());
  646. }
  647. public void addMethod(CtMethod m) throws CannotCompileException {
  648. checkModify();
  649. if (m.getDeclaringClass() != this)
  650. throw new CannotCompileException("cannot add");
  651. getMethodsCache();
  652. methodsCache = CtMethod.append(methodsCache, m);
  653. getClassFile2().addMethod(m.getMethodInfo2());
  654. if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
  655. setModifiers(getModifiers() | Modifier.ABSTRACT);
  656. }
  657. public byte[] getAttribute(String name) {
  658. AttributeInfo ai = getClassFile2().getAttribute(name);
  659. if (ai == null)
  660. return null;
  661. else
  662. return ai.get();
  663. }
  664. public void setAttribute(String name, byte[] data) {
  665. checkModify();
  666. ClassFile cf = getClassFile2();
  667. cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
  668. }
  669. public void instrument(CodeConverter converter)
  670. throws CannotCompileException
  671. {
  672. checkModify();
  673. ClassFile cf = getClassFile2();
  674. ConstPool cp = cf.getConstPool();
  675. List list = cf.getMethods();
  676. int n = list.size();
  677. for (int i = 0; i < n; ++i) {
  678. MethodInfo minfo = (MethodInfo)list.get(i);
  679. converter.doit(this, minfo, cp);
  680. }
  681. }
  682. public void instrument(ExprEditor editor)
  683. throws CannotCompileException
  684. {
  685. checkModify();
  686. ClassFile cf = getClassFile2();
  687. List list = cf.getMethods();
  688. int n = list.size();
  689. for (int i = 0; i < n; ++i) {
  690. MethodInfo minfo = (MethodInfo)list.get(i);
  691. editor.doit(this, minfo);
  692. }
  693. }
  694. public void toBytecode(DataOutputStream out)
  695. throws CannotCompileException, IOException
  696. {
  697. try {
  698. if (isModified()) {
  699. ClassFile cf = getClassFile2();
  700. modifyClassConstructor(cf);
  701. modifyConstructors(cf);
  702. cf.write(out);
  703. out.flush();
  704. }
  705. else
  706. classPool.writeClassfile(getName(), out);
  707. wasFrozen = true;
  708. }
  709. catch (NotFoundException e) {
  710. throw new CannotCompileException(e);
  711. }
  712. catch (IOException e) {
  713. throw new CannotCompileException(e);
  714. }
  715. }
  716. protected void modifyClassConstructor(ClassFile cf)
  717. throws CannotCompileException, NotFoundException
  718. {
  719. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  720. Javac jv = new Javac(code, this);
  721. int stacksize = 0;
  722. boolean doInit = false;
  723. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  724. CtField f = fi.field;
  725. if (Modifier.isStatic(f.getModifiers())) {
  726. doInit = true;
  727. int s = fi.init.compileIfStatic(f.getType(), f.getName(),
  728. code, jv);
  729. if (stacksize < s)
  730. stacksize = s;
  731. }
  732. }
  733. if (doInit) // need an initializer for static fileds.
  734. modifyClassConstructor(cf, code, stacksize, 0);
  735. }
  736. private void modifyClassConstructor(ClassFile cf, Bytecode code,
  737. int stacksize, int localsize)
  738. throws CannotCompileException
  739. {
  740. MethodInfo m = cf.getStaticInitializer();
  741. if (m == null) {
  742. code.add(Bytecode.RETURN);
  743. code.setMaxStack(stacksize);
  744. code.setMaxLocals(localsize);
  745. m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
  746. m.setAccessFlags(AccessFlag.STATIC);
  747. m.setCodeAttribute(code.toCodeAttribute());
  748. cf.addMethod(m);
  749. }
  750. else {
  751. CodeAttribute codeAttr = m.getCodeAttribute();
  752. if (codeAttr == null)
  753. throw new CannotCompileException("empty <clinit>");
  754. try {
  755. CodeIterator it = codeAttr.iterator();
  756. int pos = it.insertEx(code.get());
  757. it.insert(code.getExceptionTable(), pos);
  758. int maxstack = codeAttr.getMaxStack();
  759. if (maxstack < stacksize)
  760. codeAttr.setMaxStack(stacksize);
  761. int maxlocals = codeAttr.getMaxLocals();
  762. if (maxlocals < localsize)
  763. codeAttr.setMaxLocals(localsize);
  764. }
  765. catch (BadBytecode e) {
  766. throw new CannotCompileException(e);
  767. }
  768. }
  769. }
  770. protected void modifyConstructors(ClassFile cf)
  771. throws CannotCompileException, NotFoundException
  772. {
  773. if (fieldInitializers == null)
  774. return;
  775. ConstPool cp = cf.getConstPool();
  776. List list = cf.getMethods();
  777. int n = list.size();
  778. for (int i = 0; i < n; ++i) {
  779. MethodInfo minfo = (MethodInfo)list.get(i);
  780. if (minfo.isConstructor()) {
  781. CodeAttribute codeAttr = minfo.getCodeAttribute();
  782. if (codeAttr != null)
  783. try {
  784. Bytecode init = new Bytecode(cp, 0,
  785. codeAttr.getMaxLocals());
  786. CtClass[] params
  787. = Descriptor.getParameterTypes(
  788. minfo.getDescriptor(),
  789. classPool);
  790. int stacksize = makeFieldInitializer(init, params);
  791. insertAuxInitializer(codeAttr, init, stacksize);
  792. }
  793. catch (BadBytecode e) {
  794. throw new CannotCompileException(e);
  795. }
  796. }
  797. }
  798. }
  799. private static void insertAuxInitializer(CodeAttribute codeAttr,
  800. Bytecode initializer,
  801. int stacksize)
  802. throws BadBytecode
  803. {
  804. CodeIterator it = codeAttr.iterator();
  805. int index = it.skipSuperConstructor();
  806. if (index < 0) {
  807. index = it.skipThisConstructor();
  808. if (index >= 0)
  809. return; // this() is called.
  810. // Neither this() or super() is called.
  811. }
  812. int pos = it.insertEx(initializer.get());
  813. it.insert(initializer.getExceptionTable(), pos);
  814. int maxstack = codeAttr.getMaxStack();
  815. if (maxstack < stacksize)
  816. codeAttr.setMaxStack(stacksize);
  817. }
  818. private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
  819. throws CannotCompileException, NotFoundException
  820. {
  821. int stacksize = 0;
  822. Javac jv = new Javac(code, this);
  823. try {
  824. jv.recordParams(parameters, false);
  825. }
  826. catch (CompileError e) {
  827. throw new CannotCompileException(e);
  828. }
  829. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  830. CtField f = fi.field;
  831. if (!Modifier.isStatic(f.getModifiers())) {
  832. int s = fi.init.compile(f.getType(), f.getName(), code,
  833. parameters, jv);
  834. if (stacksize < s)
  835. stacksize = s;
  836. }
  837. }
  838. return stacksize;
  839. }
  840. // Methods used by CtNewWrappedMethod
  841. Hashtable getHiddenMethods() {
  842. if (hiddenMethods == null)
  843. hiddenMethods = new Hashtable();
  844. return hiddenMethods;
  845. }
  846. int getUniqueNumber() { return uniqueNumberSeed++; }
  847. }
  848. class FieldInitLink {
  849. FieldInitLink next;
  850. CtField field;
  851. CtField.Initializer init;
  852. FieldInitLink(CtField f, CtField.Initializer i) {
  853. next = null;
  854. field = f;
  855. init = i;
  856. }
  857. }