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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later,
  9. * or the Apache License Version 2.0.
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. */
  16. package javassist;
  17. import java.io.BufferedInputStream;
  18. import java.io.ByteArrayInputStream;
  19. import java.io.ByteArrayOutputStream;
  20. import java.io.DataInputStream;
  21. import java.io.DataOutputStream;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.lang.ref.Reference;
  25. import java.lang.ref.WeakReference;
  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. import java.util.Map;
  32. import java.util.Set;
  33. import javassist.bytecode.AccessFlag;
  34. import javassist.bytecode.AnnotationsAttribute;
  35. import javassist.bytecode.AttributeInfo;
  36. import javassist.bytecode.BadBytecode;
  37. import javassist.bytecode.Bytecode;
  38. import javassist.bytecode.ClassFile;
  39. import javassist.bytecode.CodeAttribute;
  40. import javassist.bytecode.CodeIterator;
  41. import javassist.bytecode.ConstPool;
  42. import javassist.bytecode.ConstantAttribute;
  43. import javassist.bytecode.Descriptor;
  44. import javassist.bytecode.EnclosingMethodAttribute;
  45. import javassist.bytecode.FieldInfo;
  46. import javassist.bytecode.InnerClassesAttribute;
  47. import javassist.bytecode.MethodInfo;
  48. import javassist.bytecode.ParameterAnnotationsAttribute;
  49. import javassist.bytecode.SignatureAttribute;
  50. import javassist.bytecode.annotation.Annotation;
  51. import javassist.compiler.AccessorMaker;
  52. import javassist.compiler.CompileError;
  53. import javassist.compiler.Javac;
  54. import javassist.expr.ExprEditor;
  55. /**
  56. * Class<?> types.
  57. */
  58. class CtClassType extends CtClass {
  59. ClassPool classPool;
  60. boolean wasChanged;
  61. private boolean wasFrozen;
  62. boolean wasPruned;
  63. boolean gcConstPool; // if true, the constant pool entries will be garbage collected.
  64. ClassFile classfile;
  65. byte[] rawClassfile; // backup storage
  66. private Reference<CtMember.Cache> memberCache;
  67. private AccessorMaker accessors;
  68. private FieldInitLink fieldInitializers;
  69. private Map<CtMethod,String> hiddenMethods; // must be synchronous
  70. private int uniqueNumberSeed;
  71. private boolean doPruning = ClassPool.doPruning;
  72. private int getCount;
  73. private static final int GET_THRESHOLD = 2; // see compress()
  74. CtClassType(String name, ClassPool cp) {
  75. super(name);
  76. classPool = cp;
  77. wasChanged = wasFrozen = wasPruned = gcConstPool = false;
  78. classfile = null;
  79. rawClassfile = null;
  80. memberCache = null;
  81. accessors = null;
  82. fieldInitializers = null;
  83. hiddenMethods = null;
  84. uniqueNumberSeed = 0;
  85. getCount = 0;
  86. }
  87. CtClassType(InputStream ins, ClassPool cp) throws IOException {
  88. this((String)null, cp);
  89. classfile = new ClassFile(new DataInputStream(ins));
  90. qualifiedName = classfile.getName();
  91. }
  92. CtClassType(ClassFile cf, ClassPool cp) {
  93. this((String)null, cp);
  94. classfile = cf;
  95. qualifiedName = classfile.getName();
  96. }
  97. @Override
  98. protected void extendToString(StringBuilder buffer) {
  99. if (wasChanged)
  100. buffer.append("changed ");
  101. if (wasFrozen)
  102. buffer.append("frozen ");
  103. if (wasPruned)
  104. buffer.append("pruned ");
  105. buffer.append(Modifier.toString(getModifiers()));
  106. buffer.append(" class ");
  107. buffer.append(getName());
  108. try {
  109. CtClass ext = getSuperclass();
  110. if (ext != null) {
  111. String name = ext.getName();
  112. if (!name.equals("java.lang.Object"))
  113. buffer.append(" extends ").append(ext.getName());
  114. }
  115. }
  116. catch (NotFoundException e) {
  117. buffer.append(" extends ??");
  118. }
  119. try {
  120. CtClass[] intf = getInterfaces();
  121. if (intf.length > 0)
  122. buffer.append(" implements ");
  123. for (int i = 0; i < intf.length; ++i) {
  124. buffer.append(intf[i].getName());
  125. buffer.append(", ");
  126. }
  127. }
  128. catch (NotFoundException e) {
  129. buffer.append(" extends ??");
  130. }
  131. CtMember.Cache memCache = getMembers();
  132. exToString(buffer, " fields=",
  133. memCache.fieldHead(), memCache.lastField());
  134. exToString(buffer, " constructors=",
  135. memCache.consHead(), memCache.lastCons());
  136. exToString(buffer, " methods=",
  137. memCache.methodHead(), memCache.lastMethod());
  138. }
  139. private void exToString(StringBuilder buffer, String msg,
  140. CtMember head, CtMember tail) {
  141. buffer.append(msg);
  142. while (head != tail) {
  143. head = head.next();
  144. buffer.append(head);
  145. buffer.append(", ");
  146. }
  147. }
  148. @Override
  149. public AccessorMaker getAccessorMaker() {
  150. if (accessors == null)
  151. accessors = new AccessorMaker(this);
  152. return accessors;
  153. }
  154. @Override
  155. public ClassFile getClassFile2() {
  156. return getClassFile3(true);
  157. }
  158. public ClassFile getClassFile3(boolean doCompress) {
  159. // quick path - no locking
  160. ClassFile cfile = classfile;
  161. if (cfile != null)
  162. return cfile;
  163. if (doCompress)
  164. classPool.compress();
  165. byte[] rcfile;
  166. synchronized (this) {
  167. // repeat under lock to make sure we get a consistent result (classfile might have been set by another thread)
  168. cfile = classfile;
  169. if (cfile != null)
  170. return cfile;
  171. rcfile = rawClassfile;
  172. }
  173. if (rcfile != null) {
  174. final ClassFile cf;
  175. try {
  176. cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(rcfile)));
  177. }
  178. catch (IOException e) {
  179. throw new RuntimeException(e.toString(), e);
  180. }
  181. getCount = GET_THRESHOLD;
  182. synchronized (this) {
  183. rawClassfile = null;
  184. return setClassFile(cf);
  185. }
  186. }
  187. InputStream fin = null;
  188. try {
  189. fin = classPool.openClassfile(getName());
  190. if (fin == null)
  191. throw new NotFoundException(getName());
  192. fin = new BufferedInputStream(fin);
  193. ClassFile cf = new ClassFile(new DataInputStream(fin));
  194. if (!cf.getName().equals(qualifiedName))
  195. throw new RuntimeException("cannot find " + qualifiedName + ": "
  196. + cf.getName() + " found in "
  197. + qualifiedName.replace('.', '/') + ".class");
  198. return setClassFile(cf);
  199. }
  200. catch (NotFoundException e) {
  201. throw new RuntimeException(e.toString(), e);
  202. }
  203. catch (IOException e) {
  204. throw new RuntimeException(e.toString(), e);
  205. }
  206. finally {
  207. if (fin != null)
  208. try {
  209. fin.close();
  210. }
  211. catch (IOException e) {}
  212. }
  213. }
  214. /* Inherited from CtClass. Called by get() in ClassPool.
  215. *
  216. * @see javassist.CtClass#incGetCounter()
  217. * @see #toBytecode(DataOutputStream)
  218. */
  219. @Override
  220. final void incGetCounter() { ++getCount; }
  221. /**
  222. * Invoked from ClassPool#compress().
  223. * It releases the class files that have not been recently used
  224. * if they are unmodified.
  225. */
  226. @Override
  227. void compress() {
  228. if (getCount < GET_THRESHOLD)
  229. if (!isModified() && ClassPool.releaseUnmodifiedClassFile)
  230. removeClassFile();
  231. else if (isFrozen() && !wasPruned)
  232. saveClassFile();
  233. getCount = 0;
  234. }
  235. /**
  236. * Converts a ClassFile object into a byte array
  237. * for saving memory space.
  238. */
  239. private synchronized void saveClassFile() {
  240. /* getMembers() and removeClassFile() are also synchronized.
  241. */
  242. if (classfile == null || hasMemberCache() != null)
  243. return;
  244. ByteArrayOutputStream barray = new ByteArrayOutputStream();
  245. DataOutputStream out = new DataOutputStream(barray);
  246. try {
  247. classfile.write(out);
  248. barray.close();
  249. rawClassfile = barray.toByteArray();
  250. classfile = null;
  251. }
  252. catch (IOException e) {}
  253. }
  254. private synchronized void removeClassFile() {
  255. if (classfile != null && !isModified() && hasMemberCache() == null)
  256. classfile = null;
  257. }
  258. /**
  259. * Updates {@code classfile} if it is null.
  260. */
  261. private synchronized ClassFile setClassFile(ClassFile cf) {
  262. if (classfile == null)
  263. classfile = cf;
  264. return classfile;
  265. }
  266. @Override
  267. public ClassPool getClassPool() { return classPool; }
  268. void setClassPool(ClassPool cp) { classPool = cp; }
  269. @Override
  270. public URL getURL() throws NotFoundException {
  271. URL url = classPool.find(getName());
  272. if (url == null)
  273. throw new NotFoundException(getName());
  274. return url;
  275. }
  276. @Override
  277. public boolean isModified() { return wasChanged; }
  278. @Override
  279. public boolean isFrozen() { return wasFrozen; }
  280. @Override
  281. public void freeze() { wasFrozen = true; }
  282. @Override
  283. void checkModify() throws RuntimeException {
  284. if (isFrozen()) {
  285. String msg = getName() + " class is frozen";
  286. if (wasPruned)
  287. msg += " and pruned";
  288. throw new RuntimeException(msg);
  289. }
  290. wasChanged = true;
  291. }
  292. @Override
  293. public void defrost() {
  294. checkPruned("defrost");
  295. wasFrozen = false;
  296. }
  297. @Override
  298. public boolean subtypeOf(CtClass clazz) throws NotFoundException {
  299. int i;
  300. String cname = clazz.getName();
  301. if (this == clazz || getName().equals(cname))
  302. return true;
  303. ClassFile file = getClassFile2();
  304. String supername = file.getSuperclass();
  305. if (supername != null && supername.equals(cname))
  306. return true;
  307. String[] ifs = file.getInterfaces();
  308. int num = ifs.length;
  309. for (i = 0; i < num; ++i)
  310. if (ifs[i].equals(cname))
  311. return true;
  312. if (supername != null && classPool.get(supername).subtypeOf(clazz))
  313. return true;
  314. for (i = 0; i < num; ++i)
  315. if (classPool.get(ifs[i]).subtypeOf(clazz))
  316. return true;
  317. return false;
  318. }
  319. @Override
  320. public void setName(String name) throws RuntimeException {
  321. String oldname = getName();
  322. if (name.equals(oldname))
  323. return;
  324. // check this in advance although classNameChanged() below does.
  325. classPool.checkNotFrozen(name);
  326. ClassFile cf = getClassFile2();
  327. super.setName(name);
  328. cf.setName(name);
  329. nameReplaced();
  330. classPool.classNameChanged(oldname, this);
  331. }
  332. @Override
  333. public String getGenericSignature() {
  334. SignatureAttribute sa
  335. = (SignatureAttribute)getClassFile2().getAttribute(SignatureAttribute.tag);
  336. return sa == null ? null : sa.getSignature();
  337. }
  338. @Override
  339. public void setGenericSignature(String sig) {
  340. ClassFile cf = getClassFile();
  341. SignatureAttribute sa = new SignatureAttribute(cf.getConstPool(), sig);
  342. cf.addAttribute(sa);
  343. }
  344. @Override
  345. public void replaceClassName(ClassMap classnames)
  346. throws RuntimeException
  347. {
  348. String oldClassName = getName();
  349. String newClassName
  350. = classnames.get(Descriptor.toJvmName(oldClassName));
  351. if (newClassName != null) {
  352. newClassName = Descriptor.toJavaName(newClassName);
  353. // check this in advance although classNameChanged() below does.
  354. classPool.checkNotFrozen(newClassName);
  355. }
  356. super.replaceClassName(classnames);
  357. ClassFile cf = getClassFile2();
  358. cf.renameClass(classnames);
  359. nameReplaced();
  360. if (newClassName != null) {
  361. super.setName(newClassName);
  362. classPool.classNameChanged(oldClassName, this);
  363. }
  364. }
  365. @Override
  366. public void replaceClassName(String oldname, String newname)
  367. throws RuntimeException
  368. {
  369. String thisname = getName();
  370. if (thisname.equals(oldname))
  371. setName(newname);
  372. else {
  373. super.replaceClassName(oldname, newname);
  374. getClassFile2().renameClass(oldname, newname);
  375. nameReplaced();
  376. }
  377. }
  378. @Override
  379. public boolean isInterface() {
  380. return Modifier.isInterface(getModifiers());
  381. }
  382. @Override
  383. public boolean isAnnotation() {
  384. return Modifier.isAnnotation(getModifiers());
  385. }
  386. @Override
  387. public boolean isEnum() {
  388. return Modifier.isEnum(getModifiers());
  389. }
  390. @Override
  391. public int getModifiers() {
  392. ClassFile cf = getClassFile2();
  393. int acc = cf.getAccessFlags();
  394. acc = AccessFlag.clear(acc, AccessFlag.SUPER);
  395. int inner = cf.getInnerAccessFlags();
  396. if (inner != -1) {
  397. if ((inner & AccessFlag.STATIC) != 0)
  398. acc |= AccessFlag.STATIC;
  399. if ((inner & AccessFlag.PUBLIC) != 0)
  400. acc |= AccessFlag.PUBLIC;
  401. else {
  402. acc &= ~AccessFlag.PUBLIC; //clear PUBLIC
  403. if ((inner & AccessFlag.PROTECTED) != 0)
  404. acc |= AccessFlag.PROTECTED;
  405. else if ((inner & AccessFlag.PRIVATE) != 0)
  406. acc |= AccessFlag.PRIVATE;
  407. }
  408. }
  409. return AccessFlag.toModifier(acc);
  410. }
  411. @Override
  412. public CtClass[] getNestedClasses() throws NotFoundException {
  413. ClassFile cf = getClassFile2();
  414. InnerClassesAttribute ica
  415. = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag);
  416. if (ica == null)
  417. return new CtClass[0];
  418. String thisName = cf.getName() + "$";
  419. int n = ica.tableLength();
  420. List<CtClass> list = new ArrayList<CtClass>(n);
  421. for (int i = 0; i < n; i++) {
  422. String name = ica.innerClass(i);
  423. if (name != null)
  424. if (name.startsWith(thisName)) {
  425. // if it is an immediate nested class
  426. if (name.lastIndexOf('$') < thisName.length())
  427. list.add(classPool.get(name));
  428. }
  429. }
  430. return list.toArray(new CtClass[list.size()]);
  431. }
  432. @Override
  433. public void setModifiers(int mod) {
  434. checkModify();
  435. updateInnerEntry(mod, getName(), this, true);
  436. ClassFile cf = getClassFile2();
  437. cf.setAccessFlags(AccessFlag.of(mod & ~Modifier.STATIC));
  438. }
  439. private static void updateInnerEntry(int newMod, String name, CtClass clazz, boolean outer) {
  440. ClassFile cf = clazz.getClassFile2();
  441. InnerClassesAttribute ica
  442. = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag);
  443. if (ica != null) {
  444. // If the class is a static inner class, its modifier
  445. // does not contain the static bit. Its inner class attribute
  446. // contains the static bit.
  447. int mod = newMod & ~Modifier.STATIC;
  448. int i = ica.find(name);
  449. if (i >= 0) {
  450. int isStatic = ica.accessFlags(i) & AccessFlag.STATIC;
  451. if (isStatic != 0 || !Modifier.isStatic(newMod)) {
  452. clazz.checkModify();
  453. ica.setAccessFlags(i, AccessFlag.of(mod) | isStatic);
  454. String outName = ica.outerClass(i);
  455. if (outName != null && outer)
  456. try {
  457. CtClass parent = clazz.getClassPool().get(outName);
  458. updateInnerEntry(mod, name, parent, false);
  459. }
  460. catch (NotFoundException e) {
  461. throw new RuntimeException("cannot find the declaring class: "
  462. + outName);
  463. }
  464. return;
  465. }
  466. }
  467. }
  468. if (Modifier.isStatic(newMod))
  469. throw new RuntimeException("cannot change " + Descriptor.toJavaName(name)
  470. + " into a static class");
  471. }
  472. @Override
  473. public boolean hasAnnotation(String annotationName) {
  474. ClassFile cf = getClassFile2();
  475. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  476. cf.getAttribute(AnnotationsAttribute.invisibleTag);
  477. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  478. cf.getAttribute(AnnotationsAttribute.visibleTag);
  479. return hasAnnotationType(annotationName, getClassPool(), ainfo, ainfo2);
  480. }
  481. /**
  482. * @deprecated
  483. */
  484. @Deprecated
  485. static boolean hasAnnotationType(Class<?> clz, ClassPool cp,
  486. AnnotationsAttribute a1,
  487. AnnotationsAttribute a2)
  488. {
  489. return hasAnnotationType(clz.getName(), cp, a1, a2);
  490. }
  491. static boolean hasAnnotationType(String annotationTypeName, ClassPool cp,
  492. AnnotationsAttribute a1,
  493. AnnotationsAttribute a2)
  494. {
  495. Annotation[] anno1, anno2;
  496. if (a1 == null)
  497. anno1 = null;
  498. else
  499. anno1 = a1.getAnnotations();
  500. if (a2 == null)
  501. anno2 = null;
  502. else
  503. anno2 = a2.getAnnotations();
  504. if (anno1 != null)
  505. for (int i = 0; i < anno1.length; i++)
  506. if (anno1[i].getTypeName().equals(annotationTypeName))
  507. return true;
  508. if (anno2 != null)
  509. for (int i = 0; i < anno2.length; i++)
  510. if (anno2[i].getTypeName().equals(annotationTypeName))
  511. return true;
  512. return false;
  513. }
  514. @Override
  515. public Object getAnnotation(Class<?> clz) throws ClassNotFoundException {
  516. ClassFile cf = getClassFile2();
  517. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  518. cf.getAttribute(AnnotationsAttribute.invisibleTag);
  519. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  520. cf.getAttribute(AnnotationsAttribute.visibleTag);
  521. return getAnnotationType(clz, getClassPool(), ainfo, ainfo2);
  522. }
  523. static Object getAnnotationType(Class<?> clz, ClassPool cp,
  524. AnnotationsAttribute a1, AnnotationsAttribute a2)
  525. throws ClassNotFoundException
  526. {
  527. Annotation[] anno1, anno2;
  528. if (a1 == null)
  529. anno1 = null;
  530. else
  531. anno1 = a1.getAnnotations();
  532. if (a2 == null)
  533. anno2 = null;
  534. else
  535. anno2 = a2.getAnnotations();
  536. String typeName = clz.getName();
  537. if (anno1 != null)
  538. for (int i = 0; i < anno1.length; i++)
  539. if (anno1[i].getTypeName().equals(typeName))
  540. return toAnnoType(anno1[i], cp);
  541. if (anno2 != null)
  542. for (int i = 0; i < anno2.length; i++)
  543. if (anno2[i].getTypeName().equals(typeName))
  544. return toAnnoType(anno2[i], cp);
  545. return null;
  546. }
  547. @Override
  548. public Object[] getAnnotations() throws ClassNotFoundException {
  549. return getAnnotations(false);
  550. }
  551. @Override
  552. public Object[] getAvailableAnnotations(){
  553. try {
  554. return getAnnotations(true);
  555. }
  556. catch (ClassNotFoundException e) {
  557. throw new RuntimeException("Unexpected exception ", e);
  558. }
  559. }
  560. private Object[] getAnnotations(boolean ignoreNotFound)
  561. throws ClassNotFoundException
  562. {
  563. ClassFile cf = getClassFile2();
  564. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  565. cf.getAttribute(AnnotationsAttribute.invisibleTag);
  566. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  567. cf.getAttribute(AnnotationsAttribute.visibleTag);
  568. return toAnnotationType(ignoreNotFound, getClassPool(), ainfo, ainfo2);
  569. }
  570. static Object[] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
  571. AnnotationsAttribute a1, AnnotationsAttribute a2)
  572. throws ClassNotFoundException
  573. {
  574. Annotation[] anno1, anno2;
  575. int size1, size2;
  576. if (a1 == null) {
  577. anno1 = null;
  578. size1 = 0;
  579. }
  580. else {
  581. anno1 = a1.getAnnotations();
  582. size1 = anno1.length;
  583. }
  584. if (a2 == null) {
  585. anno2 = null;
  586. size2 = 0;
  587. }
  588. else {
  589. anno2 = a2.getAnnotations();
  590. size2 = anno2.length;
  591. }
  592. if (!ignoreNotFound){
  593. Object[] result = new Object[size1 + size2];
  594. for (int i = 0; i < size1; i++)
  595. result[i] = toAnnoType(anno1[i], cp);
  596. for (int j = 0; j < size2; j++)
  597. result[j + size1] = toAnnoType(anno2[j], cp);
  598. return result;
  599. }
  600. List<Object> annotations = new ArrayList<Object>();
  601. for (int i = 0 ; i < size1 ; i++)
  602. try{
  603. annotations.add(toAnnoType(anno1[i], cp));
  604. }
  605. catch(ClassNotFoundException e){}
  606. for (int j = 0; j < size2; j++)
  607. try{
  608. annotations.add(toAnnoType(anno2[j], cp));
  609. }
  610. catch(ClassNotFoundException e){}
  611. return annotations.toArray();
  612. }
  613. static Object[][] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
  614. ParameterAnnotationsAttribute a1,
  615. ParameterAnnotationsAttribute a2,
  616. MethodInfo minfo)
  617. throws ClassNotFoundException
  618. {
  619. int numParameters = 0;
  620. if (a1 != null)
  621. numParameters = a1.numParameters();
  622. else if (a2 != null)
  623. numParameters = a2.numParameters();
  624. else
  625. numParameters = Descriptor.numOfParameters(minfo.getDescriptor());
  626. Object[][] result = new Object[numParameters][];
  627. for (int i = 0; i < numParameters; i++) {
  628. Annotation[] anno1, anno2;
  629. int size1, size2;
  630. if (a1 == null) {
  631. anno1 = null;
  632. size1 = 0;
  633. }
  634. else {
  635. anno1 = a1.getAnnotations()[i];
  636. size1 = anno1.length;
  637. }
  638. if (a2 == null) {
  639. anno2 = null;
  640. size2 = 0;
  641. }
  642. else {
  643. anno2 = a2.getAnnotations()[i];
  644. size2 = anno2.length;
  645. }
  646. if (!ignoreNotFound){
  647. result[i] = new Object[size1 + size2];
  648. for (int j = 0; j < size1; ++j)
  649. result[i][j] = toAnnoType(anno1[j], cp);
  650. for (int j = 0; j < size2; ++j)
  651. result[i][j + size1] = toAnnoType(anno2[j], cp);
  652. }
  653. else{
  654. List<Object> annotations = new ArrayList<Object>();
  655. for (int j = 0 ; j < size1 ; j++){
  656. try{
  657. annotations.add(toAnnoType(anno1[j], cp));
  658. }
  659. catch(ClassNotFoundException e){}
  660. }
  661. for (int j = 0; j < size2; j++){
  662. try{
  663. annotations.add(toAnnoType(anno2[j], cp));
  664. }
  665. catch(ClassNotFoundException e){}
  666. }
  667. result[i] = annotations.toArray();
  668. }
  669. }
  670. return result;
  671. }
  672. private static Object toAnnoType(Annotation anno, ClassPool cp)
  673. throws ClassNotFoundException
  674. {
  675. try {
  676. ClassLoader cl = cp.getClassLoader();
  677. return anno.toAnnotationType(cl, cp);
  678. }
  679. catch (ClassNotFoundException e) {
  680. ClassLoader cl2 = cp.getClass().getClassLoader();
  681. try {
  682. return anno.toAnnotationType(cl2, cp);
  683. }
  684. catch (ClassNotFoundException e2){
  685. try {
  686. Class<?> clazz = cp.get(anno.getTypeName()).toClass();
  687. return javassist.bytecode.annotation.AnnotationImpl.make(
  688. clazz.getClassLoader(),
  689. clazz, cp, anno);
  690. }
  691. catch (Throwable e3) {
  692. throw new ClassNotFoundException(anno.getTypeName());
  693. }
  694. }
  695. }
  696. }
  697. @Override
  698. public boolean subclassOf(CtClass superclass) {
  699. if (superclass == null)
  700. return false;
  701. String superName = superclass.getName();
  702. CtClass curr = this;
  703. try {
  704. while (curr != null) {
  705. if (curr.getName().equals(superName))
  706. return true;
  707. curr = curr.getSuperclass();
  708. }
  709. }
  710. catch (Exception ignored) {}
  711. return false;
  712. }
  713. @Override
  714. public CtClass getSuperclass() throws NotFoundException {
  715. String supername = getClassFile2().getSuperclass();
  716. if (supername == null)
  717. return null;
  718. return classPool.get(supername);
  719. }
  720. @Override
  721. public void setSuperclass(CtClass clazz) throws CannotCompileException {
  722. checkModify();
  723. if (isInterface())
  724. addInterface(clazz);
  725. else
  726. getClassFile2().setSuperclass(clazz.getName());
  727. }
  728. @Override
  729. public CtClass[] getInterfaces() throws NotFoundException {
  730. String[] ifs = getClassFile2().getInterfaces();
  731. int num = ifs.length;
  732. CtClass[] ifc = new CtClass[num];
  733. for (int i = 0; i < num; ++i)
  734. ifc[i] = classPool.get(ifs[i]);
  735. return ifc;
  736. }
  737. @Override
  738. public void setInterfaces(CtClass[] list) {
  739. checkModify();
  740. String[] ifs;
  741. if (list == null)
  742. ifs = new String[0];
  743. else {
  744. int num = list.length;
  745. ifs = new String[num];
  746. for (int i = 0; i < num; ++i)
  747. ifs[i] = list[i].getName();
  748. }
  749. getClassFile2().setInterfaces(ifs);
  750. }
  751. @Override
  752. public void addInterface(CtClass anInterface) {
  753. checkModify();
  754. if (anInterface != null)
  755. getClassFile2().addInterface(anInterface.getName());
  756. }
  757. @Override
  758. public CtClass getDeclaringClass() throws NotFoundException {
  759. ClassFile cf = getClassFile2();
  760. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  761. InnerClassesAttribute.tag);
  762. if (ica == null)
  763. return null;
  764. String name = getName();
  765. int n = ica.tableLength();
  766. for (int i = 0; i < n; ++i)
  767. if (name.equals(ica.innerClass(i))) {
  768. String outName = ica.outerClass(i);
  769. if (outName != null)
  770. return classPool.get(outName);
  771. // maybe anonymous or local class.
  772. EnclosingMethodAttribute ema
  773. = (EnclosingMethodAttribute)cf.getAttribute(
  774. EnclosingMethodAttribute.tag);
  775. if (ema != null)
  776. return classPool.get(ema.className());
  777. }
  778. return null;
  779. }
  780. @Override
  781. public CtBehavior getEnclosingBehavior() throws NotFoundException
  782. {
  783. ClassFile cf = getClassFile2();
  784. EnclosingMethodAttribute ema
  785. = (EnclosingMethodAttribute)cf.getAttribute(
  786. EnclosingMethodAttribute.tag);
  787. if (ema == null)
  788. return null;
  789. CtClass enc = classPool.get(ema.className());
  790. String name = ema.methodName();
  791. if (MethodInfo.nameInit.equals(name))
  792. return enc.getConstructor(ema.methodDescriptor());
  793. else if(MethodInfo.nameClinit.equals(name))
  794. return enc.getClassInitializer();
  795. else
  796. return enc.getMethod(name, ema.methodDescriptor());
  797. }
  798. @Override
  799. public CtClass makeNestedClass(String name, boolean isStatic)
  800. {
  801. if (!isStatic)
  802. throw new RuntimeException(
  803. "sorry, only nested static class is supported");
  804. checkModify();
  805. CtClass c = classPool.makeNestedClass(getName() + "$" + name);
  806. ClassFile cf = getClassFile2();
  807. ClassFile cf2 = c.getClassFile2();
  808. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  809. InnerClassesAttribute.tag);
  810. if (ica == null) {
  811. ica = new InnerClassesAttribute(cf.getConstPool());
  812. cf.addAttribute(ica);
  813. }
  814. ica.append(c.getName(), this.getName(), name,
  815. (cf2.getAccessFlags() & ~AccessFlag.SUPER) | AccessFlag.STATIC);
  816. cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
  817. return c;
  818. }
  819. /* flush cached names.
  820. */
  821. private void nameReplaced() {
  822. CtMember.Cache cache = hasMemberCache();
  823. if (cache != null) {
  824. CtMember mth = cache.methodHead();
  825. CtMember tail = cache.lastMethod();
  826. while (mth != tail) {
  827. mth = mth.next();
  828. mth.nameReplaced();
  829. }
  830. }
  831. }
  832. /**
  833. * Returns null if members are not cached.
  834. */
  835. protected CtMember.Cache hasMemberCache() {
  836. if (memberCache != null)
  837. return memberCache.get();
  838. return null;
  839. }
  840. protected synchronized CtMember.Cache getMembers() {
  841. CtMember.Cache cache = null;
  842. if (memberCache == null
  843. || (cache = memberCache.get()) == null) {
  844. cache = new CtMember.Cache(this);
  845. makeFieldCache(cache);
  846. makeBehaviorCache(cache);
  847. memberCache = new WeakReference<CtMember.Cache>(cache);
  848. }
  849. return cache;
  850. }
  851. private void makeFieldCache(CtMember.Cache cache) {
  852. List<FieldInfo> fields = getClassFile3(false).getFields();
  853. for (FieldInfo finfo:fields)
  854. cache.addField(new CtField(finfo, this));
  855. }
  856. private void makeBehaviorCache(CtMember.Cache cache) {
  857. List<MethodInfo> methods = getClassFile3(false).getMethods();
  858. for (MethodInfo minfo:methods)
  859. if (minfo.isMethod())
  860. cache.addMethod(new CtMethod(minfo, this));
  861. else
  862. cache.addConstructor(new CtConstructor(minfo, this));
  863. }
  864. @Override
  865. public CtField[] getFields() {
  866. List<CtMember> alist = new ArrayList<CtMember>();
  867. getFields(alist, this);
  868. return alist.toArray(new CtField[alist.size()]);
  869. }
  870. private static void getFields(List<CtMember> alist, CtClass cc) {
  871. if (cc == null)
  872. return;
  873. try {
  874. getFields(alist, cc.getSuperclass());
  875. }
  876. catch (NotFoundException e) {}
  877. try {
  878. CtClass[] ifs = cc.getInterfaces();
  879. for (CtClass ctc : ifs)
  880. getFields(alist, ctc);
  881. }
  882. catch (NotFoundException e) {}
  883. CtMember.Cache memCache = ((CtClassType)cc).getMembers();
  884. CtMember field = memCache.fieldHead();
  885. CtMember tail = memCache.lastField();
  886. while (field != tail) {
  887. field = field.next();
  888. if (!Modifier.isPrivate(field.getModifiers()))
  889. alist.add(field);
  890. }
  891. }
  892. @Override
  893. public CtField getField(String name, String desc) throws NotFoundException {
  894. CtField f = getField2(name, desc);
  895. return checkGetField(f, name, desc);
  896. }
  897. private CtField checkGetField(CtField f, String name, String desc)
  898. throws NotFoundException
  899. {
  900. if (f == null) {
  901. String msg = "field: " + name;
  902. if (desc != null)
  903. msg += " type " + desc;
  904. throw new NotFoundException(msg + " in " + getName());
  905. }
  906. return f;
  907. }
  908. @Override
  909. CtField getField2(String name, String desc) {
  910. CtField df = getDeclaredField2(name, desc);
  911. if (df != null)
  912. return df;
  913. try {
  914. CtClass[] ifs = getInterfaces();
  915. for (CtClass ctc : ifs) {
  916. CtField f = ctc.getField2(name, desc);
  917. if (f != null)
  918. return f;
  919. }
  920. CtClass s = getSuperclass();
  921. if (s != null)
  922. return s.getField2(name, desc);
  923. }
  924. catch (NotFoundException e) {}
  925. return null;
  926. }
  927. @Override
  928. public CtField[] getDeclaredFields() {
  929. CtMember.Cache memCache = getMembers();
  930. CtMember field = memCache.fieldHead();
  931. CtMember tail = memCache.lastField();
  932. int num = CtMember.Cache.count(field, tail);
  933. CtField[] cfs = new CtField[num];
  934. int i = 0;
  935. while (field != tail) {
  936. field = field.next();
  937. cfs[i++] = (CtField)field;
  938. }
  939. return cfs;
  940. }
  941. @Override
  942. public CtField getDeclaredField(String name) throws NotFoundException {
  943. return getDeclaredField(name, null);
  944. }
  945. @Override
  946. public CtField getDeclaredField(String name, String desc) throws NotFoundException {
  947. CtField f = getDeclaredField2(name, desc);
  948. return checkGetField(f, name, desc);
  949. }
  950. private CtField getDeclaredField2(String name, String desc) {
  951. CtMember.Cache memCache = getMembers();
  952. CtMember field = memCache.fieldHead();
  953. CtMember tail = memCache.lastField();
  954. while (field != tail) {
  955. field = field.next();
  956. if (field.getName().equals(name)
  957. && (desc == null || desc.equals(field.getSignature())))
  958. return (CtField)field;
  959. }
  960. return null;
  961. }
  962. @Override
  963. public CtBehavior[] getDeclaredBehaviors() {
  964. CtMember.Cache memCache = getMembers();
  965. CtMember cons = memCache.consHead();
  966. CtMember consTail = memCache.lastCons();
  967. int cnum = CtMember.Cache.count(cons, consTail);
  968. CtMember mth = memCache.methodHead();
  969. CtMember mthTail = memCache.lastMethod();
  970. int mnum = CtMember.Cache.count(mth, mthTail);
  971. CtBehavior[] cb = new CtBehavior[cnum + mnum];
  972. int i = 0;
  973. while (cons != consTail) {
  974. cons = cons.next();
  975. cb[i++] = (CtBehavior)cons;
  976. }
  977. while (mth != mthTail) {
  978. mth = mth.next();
  979. cb[i++] = (CtBehavior)mth;
  980. }
  981. return cb;
  982. }
  983. @Override
  984. public CtConstructor[] getConstructors() {
  985. CtMember.Cache memCache = getMembers();
  986. CtMember cons = memCache.consHead();
  987. CtMember consTail = memCache.lastCons();
  988. int n = 0;
  989. CtMember mem = cons;
  990. while (mem != consTail) {
  991. mem = mem.next();
  992. if (isPubCons((CtConstructor)mem))
  993. n++;
  994. }
  995. CtConstructor[] result = new CtConstructor[n];
  996. int i = 0;
  997. mem = cons;
  998. while (mem != consTail) {
  999. mem = mem.next();
  1000. CtConstructor cc = (CtConstructor)mem;
  1001. if (isPubCons(cc))
  1002. result[i++] = cc;
  1003. }
  1004. return result;
  1005. }
  1006. private static boolean isPubCons(CtConstructor cons) {
  1007. return !Modifier.isPrivate(cons.getModifiers())
  1008. && cons.isConstructor();
  1009. }
  1010. @Override
  1011. public CtConstructor getConstructor(String desc)
  1012. throws NotFoundException
  1013. {
  1014. CtMember.Cache memCache = getMembers();
  1015. CtMember cons = memCache.consHead();
  1016. CtMember consTail = memCache.lastCons();
  1017. while (cons != consTail) {
  1018. cons = cons.next();
  1019. CtConstructor cc = (CtConstructor)cons;
  1020. if (cc.getMethodInfo2().getDescriptor().equals(desc)
  1021. && cc.isConstructor())
  1022. return cc;
  1023. }
  1024. return super.getConstructor(desc);
  1025. }
  1026. @Override
  1027. public CtConstructor[] getDeclaredConstructors() {
  1028. CtMember.Cache memCache = getMembers();
  1029. CtMember cons = memCache.consHead();
  1030. CtMember consTail = memCache.lastCons();
  1031. int n = 0;
  1032. CtMember mem = cons;
  1033. while (mem != consTail) {
  1034. mem = mem.next();
  1035. CtConstructor cc = (CtConstructor)mem;
  1036. if (cc.isConstructor())
  1037. n++;
  1038. }
  1039. CtConstructor[] result = new CtConstructor[n];
  1040. int i = 0;
  1041. mem = cons;
  1042. while (mem != consTail) {
  1043. mem = mem.next();
  1044. CtConstructor cc = (CtConstructor)mem;
  1045. if (cc.isConstructor())
  1046. result[i++] = cc;
  1047. }
  1048. return result;
  1049. }
  1050. @Override
  1051. public CtConstructor getClassInitializer() {
  1052. CtMember.Cache memCache = getMembers();
  1053. CtMember cons = memCache.consHead();
  1054. CtMember consTail = memCache.lastCons();
  1055. while (cons != consTail) {
  1056. cons = cons.next();
  1057. CtConstructor cc = (CtConstructor)cons;
  1058. if (cc.isClassInitializer())
  1059. return cc;
  1060. }
  1061. return null;
  1062. }
  1063. @Override
  1064. public CtMethod[] getMethods() {
  1065. Map<String,CtMember> h = new HashMap<String,CtMember>();
  1066. getMethods0(h, this);
  1067. return h.values().toArray(new CtMethod[h.size()]);
  1068. }
  1069. private static void getMethods0(Map<String,CtMember> h, CtClass cc) {
  1070. try {
  1071. CtClass[] ifs = cc.getInterfaces();
  1072. for (CtClass ctc : ifs)
  1073. getMethods0(h, ctc);
  1074. }
  1075. catch (NotFoundException e) {}
  1076. try {
  1077. CtClass s = cc.getSuperclass();
  1078. if (s != null)
  1079. getMethods0(h, s);
  1080. }
  1081. catch (NotFoundException e) {}
  1082. if (cc instanceof CtClassType) {
  1083. CtMember.Cache memCache = ((CtClassType)cc).getMembers();
  1084. CtMember mth = memCache.methodHead();
  1085. CtMember mthTail = memCache.lastMethod();
  1086. while (mth != mthTail) {
  1087. mth = mth.next();
  1088. if (!Modifier.isPrivate(mth.getModifiers()))
  1089. h.put(((CtMethod)mth).getStringRep(), mth);
  1090. }
  1091. }
  1092. }
  1093. @Override
  1094. public CtMethod getMethod(String name, String desc)
  1095. throws NotFoundException
  1096. {
  1097. CtMethod m = getMethod0(this, name, desc);
  1098. if (m != null)
  1099. return m;
  1100. throw new NotFoundException(name + "(..) is not found in "
  1101. + getName());
  1102. }
  1103. private static CtMethod getMethod0(CtClass cc,
  1104. String name, String desc) {
  1105. if (cc instanceof CtClassType) {
  1106. CtMember.Cache memCache = ((CtClassType)cc).getMembers();
  1107. CtMember mth = memCache.methodHead();
  1108. CtMember mthTail = memCache.lastMethod();
  1109. while (mth != mthTail) {
  1110. mth = mth.next();
  1111. if (mth.getName().equals(name)
  1112. && ((CtMethod)mth).getMethodInfo2().getDescriptor().equals(desc))
  1113. return (CtMethod)mth;
  1114. }
  1115. }
  1116. try {
  1117. CtClass s = cc.getSuperclass();
  1118. if (s != null) {
  1119. CtMethod m = getMethod0(s, name, desc);
  1120. if (m != null)
  1121. return m;
  1122. }
  1123. }
  1124. catch (NotFoundException e) {}
  1125. try {
  1126. CtClass[] ifs = cc.getInterfaces();
  1127. for (CtClass ctc : ifs) {
  1128. CtMethod m = getMethod0(ctc, name, desc);
  1129. if (m != null)
  1130. return m;
  1131. }
  1132. }
  1133. catch (NotFoundException e) {}
  1134. return null;
  1135. }
  1136. @Override
  1137. public CtMethod[] getDeclaredMethods() {
  1138. CtMember.Cache memCache = getMembers();
  1139. CtMember mth = memCache.methodHead();
  1140. CtMember mthTail = memCache.lastMethod();
  1141. List<CtMember> methods = new ArrayList<CtMember>();
  1142. while (mth != mthTail) {
  1143. mth = mth.next();
  1144. methods.add(mth);
  1145. }
  1146. return methods.toArray(new CtMethod[methods.size()]);
  1147. }
  1148. @Override
  1149. public CtMethod[] getDeclaredMethods(String name) throws NotFoundException {
  1150. CtMember.Cache memCache = getMembers();
  1151. CtMember mth = memCache.methodHead();
  1152. CtMember mthTail = memCache.lastMethod();
  1153. List<CtMember> methods = new ArrayList<CtMember>();
  1154. while (mth != mthTail) {
  1155. mth = mth.next();
  1156. if (mth.getName().equals(name))
  1157. methods.add(mth);
  1158. }
  1159. return methods.toArray(new CtMethod[methods.size()]);
  1160. }
  1161. @Override
  1162. public CtMethod getDeclaredMethod(String name) throws NotFoundException {
  1163. CtMember.Cache memCache = getMembers();
  1164. CtMember mth = memCache.methodHead();
  1165. CtMember mthTail = memCache.lastMethod();
  1166. while (mth != mthTail) {
  1167. mth = mth.next();
  1168. if (mth.getName().equals(name))
  1169. return (CtMethod)mth;
  1170. }
  1171. throw new NotFoundException(name + "(..) is not found in "
  1172. + getName());
  1173. }
  1174. @Override
  1175. public CtMethod getDeclaredMethod(String name, CtClass[] params)
  1176. throws NotFoundException
  1177. {
  1178. String desc = Descriptor.ofParameters(params);
  1179. CtMember.Cache memCache = getMembers();
  1180. CtMember mth = memCache.methodHead();
  1181. CtMember mthTail = memCache.lastMethod();
  1182. while (mth != mthTail) {
  1183. mth = mth.next();
  1184. if (mth.getName().equals(name)
  1185. && ((CtMethod)mth).getMethodInfo2().getDescriptor().startsWith(desc))
  1186. return (CtMethod)mth;
  1187. }
  1188. throw new NotFoundException(name + "(..) is not found in "
  1189. + getName());
  1190. }
  1191. @Override
  1192. public void addField(CtField f, String init)
  1193. throws CannotCompileException
  1194. {
  1195. addField(f, CtField.Initializer.byExpr(init));
  1196. }
  1197. @Override
  1198. public void addField(CtField f, CtField.Initializer init)
  1199. throws CannotCompileException
  1200. {
  1201. checkModify();
  1202. if (f.getDeclaringClass() != this)
  1203. throw new CannotCompileException("cannot add");
  1204. if (init == null)
  1205. init = f.getInit();
  1206. if (init != null) {
  1207. init.check(f.getSignature());
  1208. int mod = f.getModifiers();
  1209. if (Modifier.isStatic(mod) && Modifier.isFinal(mod))
  1210. try {
  1211. ConstPool cp = getClassFile2().getConstPool();
  1212. int index = init.getConstantValue(cp, f.getType());
  1213. if (index != 0) {
  1214. f.getFieldInfo2().addAttribute(new ConstantAttribute(cp, index));
  1215. init = null;
  1216. }
  1217. }
  1218. catch (NotFoundException e) {}
  1219. }
  1220. getMembers().addField(f);
  1221. getClassFile2().addField(f.getFieldInfo2());
  1222. if (init != null) {
  1223. FieldInitLink fil = new FieldInitLink(f, init);
  1224. FieldInitLink link = fieldInitializers;
  1225. if (link == null)
  1226. fieldInitializers = fil;
  1227. else {
  1228. while (link.next != null)
  1229. link = link.next;
  1230. link.next = fil;
  1231. }
  1232. }
  1233. }
  1234. @Override
  1235. public void removeField(CtField f) throws NotFoundException {
  1236. checkModify();
  1237. FieldInfo fi = f.getFieldInfo2();
  1238. ClassFile cf = getClassFile2();
  1239. if (cf.getFields().remove(fi)) {
  1240. getMembers().remove(f);
  1241. gcConstPool = true;
  1242. }
  1243. else
  1244. throw new NotFoundException(f.toString());
  1245. }
  1246. @Override
  1247. public CtConstructor makeClassInitializer()
  1248. throws CannotCompileException
  1249. {
  1250. CtConstructor clinit = getClassInitializer();
  1251. if (clinit != null)
  1252. return clinit;
  1253. checkModify();
  1254. ClassFile cf = getClassFile2();
  1255. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  1256. modifyClassConstructor(cf, code, 0, 0);
  1257. return getClassInitializer();
  1258. }
  1259. @Override
  1260. public void addConstructor(CtConstructor c)
  1261. throws CannotCompileException
  1262. {
  1263. checkModify();
  1264. if (c.getDeclaringClass() != this)
  1265. throw new CannotCompileException("cannot add");
  1266. getMembers().addConstructor(c);
  1267. getClassFile2().addMethod(c.getMethodInfo2());
  1268. }
  1269. @Override
  1270. public void removeConstructor(CtConstructor m) throws NotFoundException {
  1271. checkModify();
  1272. MethodInfo mi = m.getMethodInfo2();
  1273. ClassFile cf = getClassFile2();
  1274. if (cf.getMethods().remove(mi)) {
  1275. getMembers().remove(m);
  1276. gcConstPool = true;
  1277. }
  1278. else
  1279. throw new NotFoundException(m.toString());
  1280. }
  1281. @Override
  1282. public void addMethod(CtMethod m) throws CannotCompileException {
  1283. checkModify();
  1284. if (m.getDeclaringClass() != this)
  1285. throw new CannotCompileException("bad declaring class");
  1286. int mod = m.getModifiers();
  1287. if ((getModifiers() & Modifier.INTERFACE) != 0) {
  1288. if (Modifier.isProtected(mod) || Modifier.isPrivate(mod))
  1289. throw new CannotCompileException(
  1290. "an interface method must be public: " + m.toString());
  1291. m.setModifiers(mod | Modifier.PUBLIC);
  1292. }
  1293. getMembers().addMethod(m);
  1294. getClassFile2().addMethod(m.getMethodInfo2());
  1295. if ((mod & Modifier.ABSTRACT) != 0)
  1296. setModifiers(getModifiers() | Modifier.ABSTRACT);
  1297. }
  1298. @Override
  1299. public void removeMethod(CtMethod m) throws NotFoundException
  1300. {
  1301. checkModify();
  1302. MethodInfo mi = m.getMethodInfo2();
  1303. ClassFile cf = getClassFile2();
  1304. if (cf.getMethods().remove(mi)) {
  1305. getMembers().remove(m);
  1306. gcConstPool = true;
  1307. }
  1308. else
  1309. throw new NotFoundException(m.toString());
  1310. }
  1311. @Override
  1312. public byte[] getAttribute(String name)
  1313. {
  1314. AttributeInfo ai = getClassFile2().getAttribute(name);
  1315. if (ai == null)
  1316. return null;
  1317. return ai.get();
  1318. }
  1319. @Override
  1320. public void setAttribute(String name, byte[] data)
  1321. {
  1322. checkModify();
  1323. ClassFile cf = getClassFile2();
  1324. cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
  1325. }
  1326. @Override
  1327. public void instrument(CodeConverter converter)
  1328. throws CannotCompileException
  1329. {
  1330. checkModify();
  1331. ClassFile cf = getClassFile2();
  1332. ConstPool cp = cf.getConstPool();
  1333. List<MethodInfo> methods = cf.getMethods();
  1334. for (MethodInfo minfo: methods.toArray(new MethodInfo[methods.size()]))
  1335. converter.doit(this, minfo, cp);
  1336. }
  1337. @Override
  1338. public void instrument(ExprEditor editor)
  1339. throws CannotCompileException
  1340. {
  1341. checkModify();
  1342. ClassFile cf = getClassFile2();
  1343. List<MethodInfo> methods = cf.getMethods();
  1344. for (MethodInfo minfo: methods.toArray(new MethodInfo[methods.size()]))
  1345. editor.doit(this, minfo);
  1346. }
  1347. /**
  1348. * @see javassist.CtClass#prune()
  1349. * @see javassist.CtClass#stopPruning(boolean)
  1350. */
  1351. @Override
  1352. public void prune()
  1353. {
  1354. if (wasPruned)
  1355. return;
  1356. wasPruned = wasFrozen = true;
  1357. getClassFile2().prune();
  1358. }
  1359. @Override
  1360. public void rebuildClassFile() { gcConstPool = true; }
  1361. @Override
  1362. public void toBytecode(DataOutputStream out)
  1363. throws CannotCompileException, IOException
  1364. {
  1365. try {
  1366. if (isModified()) {
  1367. checkPruned("toBytecode");
  1368. ClassFile cf = getClassFile2();
  1369. if (gcConstPool) {
  1370. cf.compact();
  1371. gcConstPool = false;
  1372. }
  1373. modifyClassConstructor(cf);
  1374. modifyConstructors(cf);
  1375. if (debugDump != null)
  1376. dumpClassFile(cf);
  1377. cf.write(out);
  1378. out.flush();
  1379. fieldInitializers = null;
  1380. if (doPruning) {
  1381. // to save memory
  1382. cf.prune();
  1383. wasPruned = true;
  1384. }
  1385. }
  1386. else {
  1387. classPool.writeClassfile(getName(), out);
  1388. // to save memory
  1389. // classfile = null;
  1390. }
  1391. getCount = 0;
  1392. wasFrozen = true;
  1393. }
  1394. catch (NotFoundException e) {
  1395. throw new CannotCompileException(e);
  1396. }
  1397. catch (IOException e) {
  1398. throw new CannotCompileException(e);
  1399. }
  1400. }
  1401. private void dumpClassFile(ClassFile cf) throws IOException
  1402. {
  1403. DataOutputStream dump = makeFileOutput(debugDump);
  1404. try {
  1405. cf.write(dump);
  1406. }
  1407. finally {
  1408. dump.close();
  1409. }
  1410. }
  1411. /* See also checkModified()
  1412. */
  1413. private void checkPruned(String method)
  1414. {
  1415. if (wasPruned)
  1416. throw new RuntimeException(method + "(): " + getName()
  1417. + " was pruned.");
  1418. }
  1419. @Override
  1420. public boolean stopPruning(boolean stop)
  1421. {
  1422. boolean prev = !doPruning;
  1423. doPruning = !stop;
  1424. return prev;
  1425. }
  1426. private void modifyClassConstructor(ClassFile cf)
  1427. throws CannotCompileException, NotFoundException
  1428. {
  1429. if (fieldInitializers == null)
  1430. return;
  1431. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  1432. Javac jv = new Javac(code, this);
  1433. int stacksize = 0;
  1434. boolean doInit = false;
  1435. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  1436. CtField f = fi.field;
  1437. if (Modifier.isStatic(f.getModifiers())) {
  1438. doInit = true;
  1439. int s = fi.init.compileIfStatic(f.getType(), f.getName(),
  1440. code, jv);
  1441. if (stacksize < s)
  1442. stacksize = s;
  1443. }
  1444. }
  1445. if (doInit) // need an initializer for static fileds.
  1446. modifyClassConstructor(cf, code, stacksize, 0);
  1447. }
  1448. private void modifyClassConstructor(ClassFile cf, Bytecode code,
  1449. int stacksize, int localsize)
  1450. throws CannotCompileException
  1451. {
  1452. MethodInfo m = cf.getStaticInitializer();
  1453. if (m == null) {
  1454. code.add(Bytecode.RETURN);
  1455. code.setMaxStack(stacksize);
  1456. code.setMaxLocals(localsize);
  1457. m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
  1458. m.setAccessFlags(AccessFlag.STATIC);
  1459. m.setCodeAttribute(code.toCodeAttribute());
  1460. cf.addMethod(m);
  1461. CtMember.Cache cache = hasMemberCache();
  1462. if (cache != null)
  1463. cache.addConstructor(new CtConstructor(m, this));
  1464. }
  1465. else {
  1466. CodeAttribute codeAttr = m.getCodeAttribute();
  1467. if (codeAttr == null)
  1468. throw new CannotCompileException("empty <clinit>");
  1469. try {
  1470. CodeIterator it = codeAttr.iterator();
  1471. int pos = it.insertEx(code.get());
  1472. it.insert(code.getExceptionTable(), pos);
  1473. int maxstack = codeAttr.getMaxStack();
  1474. if (maxstack < stacksize)
  1475. codeAttr.setMaxStack(stacksize);
  1476. int maxlocals = codeAttr.getMaxLocals();
  1477. if (maxlocals < localsize)
  1478. codeAttr.setMaxLocals(localsize);
  1479. }
  1480. catch (BadBytecode e) {
  1481. throw new CannotCompileException(e);
  1482. }
  1483. }
  1484. try {
  1485. m.rebuildStackMapIf6(classPool, cf);
  1486. }
  1487. catch (BadBytecode e) {
  1488. throw new CannotCompileException(e);
  1489. }
  1490. }
  1491. private void modifyConstructors(ClassFile cf)
  1492. throws CannotCompileException, NotFoundException
  1493. {
  1494. if (fieldInitializers == null)
  1495. return;
  1496. ConstPool cp = cf.getConstPool();
  1497. List<MethodInfo> methods = cf.getMethods();
  1498. for (MethodInfo minfo:methods) {
  1499. if (minfo.isConstructor()) {
  1500. CodeAttribute codeAttr = minfo.getCodeAttribute();
  1501. if (codeAttr != null)
  1502. try {
  1503. Bytecode init = new Bytecode(cp, 0,
  1504. codeAttr.getMaxLocals());
  1505. CtClass[] params
  1506. = Descriptor.getParameterTypes(
  1507. minfo.getDescriptor(),
  1508. classPool);
  1509. int stacksize = makeFieldInitializer(init, params);
  1510. insertAuxInitializer(codeAttr, init, stacksize);
  1511. minfo.rebuildStackMapIf6(classPool, cf);
  1512. }
  1513. catch (BadBytecode e) {
  1514. throw new CannotCompileException(e);
  1515. }
  1516. }
  1517. }
  1518. }
  1519. private static void insertAuxInitializer(CodeAttribute codeAttr,
  1520. Bytecode initializer,
  1521. int stacksize)
  1522. throws BadBytecode
  1523. {
  1524. CodeIterator it = codeAttr.iterator();
  1525. int index = it.skipSuperConstructor();
  1526. if (index < 0) {
  1527. index = it.skipThisConstructor();
  1528. if (index >= 0)
  1529. return; // this() is called.
  1530. // Neither this() or super() is called.
  1531. }
  1532. int pos = it.insertEx(initializer.get());
  1533. it.insert(initializer.getExceptionTable(), pos);
  1534. int maxstack = codeAttr.getMaxStack();
  1535. codeAttr.setMaxStack(maxstack + stacksize);
  1536. }
  1537. private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
  1538. throws CannotCompileException, NotFoundException
  1539. {
  1540. int stacksize = 0;
  1541. Javac jv = new Javac(code, this);
  1542. try {
  1543. jv.recordParams(parameters, false);
  1544. }
  1545. catch (CompileError e) {
  1546. throw new CannotCompileException(e);
  1547. }
  1548. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  1549. CtField f = fi.field;
  1550. if (!Modifier.isStatic(f.getModifiers())) {
  1551. int s = fi.init.compile(f.getType(), f.getName(), code,
  1552. parameters, jv);
  1553. if (stacksize < s)
  1554. stacksize = s;
  1555. }
  1556. }
  1557. return stacksize;
  1558. }
  1559. // Methods used by CtNewWrappedMethod
  1560. Map<CtMethod,String> getHiddenMethods() {
  1561. if (hiddenMethods == null)
  1562. hiddenMethods = new Hashtable<CtMethod,String>();
  1563. return hiddenMethods;
  1564. }
  1565. int getUniqueNumber() { return uniqueNumberSeed++; }
  1566. @Override
  1567. public String makeUniqueName(String prefix) {
  1568. Map<Object,CtClassType> table = new HashMap<Object,CtClassType>();
  1569. makeMemberList(table);
  1570. Set<Object> keys = table.keySet();
  1571. String[] methods = new String[keys.size()];
  1572. keys.toArray(methods);
  1573. if (notFindInArray(prefix, methods))
  1574. return prefix;
  1575. int i = 100;
  1576. String name;
  1577. do {
  1578. if (i > 999)
  1579. throw new RuntimeException("too many unique name");
  1580. name = prefix + i++;
  1581. } while (!notFindInArray(name, methods));
  1582. return name;
  1583. }
  1584. private static boolean notFindInArray(String prefix, String[] values) {
  1585. int len = values.length;
  1586. for (int i = 0; i < len; i++)
  1587. if (values[i].startsWith(prefix))
  1588. return false;
  1589. return true;
  1590. }
  1591. private void makeMemberList(Map<Object,CtClassType> table) {
  1592. int mod = getModifiers();
  1593. if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
  1594. try {
  1595. CtClass[] ifs = getInterfaces();
  1596. for (CtClass ic : ifs)
  1597. if (ic != null && ic instanceof CtClassType)
  1598. ((CtClassType)ic).makeMemberList(table);
  1599. }
  1600. catch (NotFoundException e) {}
  1601. try {
  1602. CtClass s = getSuperclass();
  1603. if (s != null && s instanceof CtClassType)
  1604. ((CtClassType)s).makeMemberList(table);
  1605. }
  1606. catch (NotFoundException e) {}
  1607. List<MethodInfo> methods = getClassFile2().getMethods();
  1608. for (MethodInfo minfo:methods)
  1609. table.put(minfo.getName(), this);
  1610. List<FieldInfo> fields = getClassFile2().getFields();
  1611. for (FieldInfo finfo:fields)
  1612. table.put(finfo.getName(), this);
  1613. }
  1614. }
  1615. class FieldInitLink {
  1616. FieldInitLink next;
  1617. CtField field;
  1618. CtField.Initializer init;
  1619. FieldInitLink(CtField f, CtField.Initializer i) {
  1620. next = null;
  1621. field = f;
  1622. init = i;
  1623. }
  1624. }