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

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