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

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