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.

Descriptor.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.bytecode;
  16. import javassist.ClassPool;
  17. import javassist.CtClass;
  18. import javassist.CtPrimitiveType;
  19. import javassist.NotFoundException;
  20. import java.util.Map;
  21. /**
  22. * A support class for dealing with descriptors.
  23. *
  24. * <p>See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)"
  25. */
  26. public class Descriptor {
  27. /**
  28. * Converts a class name into the internal representation used in
  29. * the JVM.
  30. *
  31. * <p>Note that <code>toJvmName(toJvmName(s))</code> is equivalent
  32. * to <code>toJvmName(s)</code>.
  33. */
  34. public static String toJvmName(String classname) {
  35. return classname.replace('.', '/');
  36. }
  37. /**
  38. * Converts a class name from the internal representation used in
  39. * the JVM to the normal one used in Java.
  40. * This method does not deal with an array type name such as
  41. * "[Ljava/lang/Object;" and "[I;". For such names, use
  42. * <code>toClassName()</code>.
  43. *
  44. * @see #toClassName(String)
  45. */
  46. public static String toJavaName(String classname) {
  47. return classname.replace('/', '.');
  48. }
  49. /**
  50. * Returns the internal representation of the class name in the
  51. * JVM.
  52. */
  53. public static String toJvmName(CtClass clazz) {
  54. if (clazz.isArray())
  55. return of(clazz);
  56. else
  57. return toJvmName(clazz.getName());
  58. }
  59. /**
  60. * Converts to a Java class name from a descriptor.
  61. *
  62. * @param descriptor type descriptor.
  63. */
  64. public static String toClassName(String descriptor) {
  65. int arrayDim = 0;
  66. int i = 0;
  67. char c = descriptor.charAt(0);
  68. while (c == '[') {
  69. ++arrayDim;
  70. c = descriptor.charAt(++i);
  71. }
  72. String name;
  73. if (c == 'L') {
  74. int i2 = descriptor.indexOf(';', i++);
  75. name = descriptor.substring(i, i2).replace('/', '.');
  76. i = i2;
  77. }
  78. else if (c == 'V')
  79. name = "void";
  80. else if (c == 'I')
  81. name = "int";
  82. else if (c == 'B')
  83. name = "byte";
  84. else if (c == 'J')
  85. name = "long";
  86. else if (c == 'D')
  87. name = "double";
  88. else if (c == 'F')
  89. name = "float";
  90. else if (c == 'C')
  91. name = "char";
  92. else if (c == 'S')
  93. name = "short";
  94. else if (c == 'Z')
  95. name = "boolean";
  96. else
  97. throw new RuntimeException("bad descriptor: " + descriptor);
  98. if (i + 1 != descriptor.length())
  99. throw new RuntimeException("multiple descriptors?: " + descriptor);
  100. if (arrayDim == 0)
  101. return name;
  102. else {
  103. StringBuffer sbuf = new StringBuffer(name);
  104. do {
  105. sbuf.append("[]");
  106. } while (--arrayDim > 0);
  107. return sbuf.toString();
  108. }
  109. }
  110. /**
  111. * Converts to a descriptor from a Java class name
  112. */
  113. public static String of(String classname) {
  114. if (classname.equals("void"))
  115. return "V";
  116. else if (classname.equals("int"))
  117. return "I";
  118. else if (classname.equals("byte"))
  119. return "B";
  120. else if (classname.equals("long"))
  121. return "J";
  122. else if (classname.equals("double"))
  123. return "D";
  124. else if (classname.equals("float"))
  125. return "F";
  126. else if (classname.equals("char"))
  127. return "C";
  128. else if (classname.equals("short"))
  129. return "S";
  130. else if (classname.equals("boolean"))
  131. return "Z";
  132. else
  133. return "L" + toJvmName(classname) + ";";
  134. }
  135. /**
  136. * Substitutes a class name
  137. * in the given descriptor string.
  138. *
  139. * @param desc descriptor string
  140. * @param oldname replaced JVM class name
  141. * @param newname substituted JVM class name
  142. *
  143. * @see Descriptor#toJvmName(String)
  144. */
  145. public static String rename(String desc, String oldname, String newname) {
  146. if (desc.indexOf(oldname) < 0)
  147. return desc;
  148. StringBuffer newdesc = new StringBuffer();
  149. int head = 0;
  150. int i = 0;
  151. for (;;) {
  152. int j = desc.indexOf('L', i);
  153. if (j < 0)
  154. break;
  155. else if (desc.startsWith(oldname, j + 1)
  156. && desc.charAt(j + oldname.length() + 1) == ';') {
  157. newdesc.append(desc.substring(head, j));
  158. newdesc.append('L');
  159. newdesc.append(newname);
  160. newdesc.append(';');
  161. head = i = j + oldname.length() + 2;
  162. }
  163. else {
  164. i = desc.indexOf(';', j) + 1;
  165. if (i < 1)
  166. break; // ';' was not found.
  167. }
  168. }
  169. if (head == 0)
  170. return desc;
  171. else {
  172. int len = desc.length();
  173. if (head < len)
  174. newdesc.append(desc.substring(head, len));
  175. return newdesc.toString();
  176. }
  177. }
  178. /**
  179. * Substitutes class names in the given descriptor string
  180. * according to the given <code>map</code>.
  181. *
  182. * @param map a map between replaced and substituted
  183. * JVM class names.
  184. * @see Descriptor#toJvmName(String)
  185. */
  186. public static String rename(String desc, Map map) {
  187. if (map == null)
  188. return desc;
  189. StringBuffer newdesc = new StringBuffer();
  190. int head = 0;
  191. int i = 0;
  192. for (;;) {
  193. int j = desc.indexOf('L', i);
  194. if (j < 0)
  195. break;
  196. int k = desc.indexOf(';', j);
  197. if (k < 0)
  198. break;
  199. i = k + 1;
  200. String name = desc.substring(j + 1, k);
  201. String name2 = (String)map.get(name);
  202. if (name2 != null) {
  203. newdesc.append(desc.substring(head, j));
  204. newdesc.append('L');
  205. newdesc.append(name2);
  206. newdesc.append(';');
  207. head = i;
  208. }
  209. }
  210. if (head == 0)
  211. return desc;
  212. else {
  213. int len = desc.length();
  214. if (head < len)
  215. newdesc.append(desc.substring(head, len));
  216. return newdesc.toString();
  217. }
  218. }
  219. /**
  220. * Returns the descriptor representing the given type.
  221. */
  222. public static String of(CtClass type) {
  223. StringBuffer sbuf = new StringBuffer();
  224. toDescriptor(sbuf, type);
  225. return sbuf.toString();
  226. }
  227. private static void toDescriptor(StringBuffer desc, CtClass type) {
  228. if (type.isArray()) {
  229. desc.append('[');
  230. try {
  231. toDescriptor(desc, type.getComponentType());
  232. }
  233. catch (NotFoundException e) {
  234. desc.append('L');
  235. String name = type.getName();
  236. desc.append(toJvmName(name.substring(0, name.length() - 2)));
  237. desc.append(';');
  238. }
  239. }
  240. else if (type.isPrimitive()) {
  241. CtPrimitiveType pt = (CtPrimitiveType)type;
  242. desc.append(pt.getDescriptor());
  243. }
  244. else { // class type
  245. desc.append('L');
  246. desc.append(type.getName().replace('.', '/'));
  247. desc.append(';');
  248. }
  249. }
  250. /**
  251. * Returns the descriptor representing a constructor receiving
  252. * the given parameter types.
  253. *
  254. * @param paramTypes parameter types
  255. */
  256. public static String ofConstructor(CtClass[] paramTypes) {
  257. return ofMethod(CtClass.voidType, paramTypes);
  258. }
  259. /**
  260. * Returns the descriptor representing a method that receives
  261. * the given parameter types and returns the given type.
  262. *
  263. * @param returnType return type
  264. * @param paramTypes parameter types
  265. */
  266. public static String ofMethod(CtClass returnType, CtClass[] paramTypes) {
  267. StringBuffer desc = new StringBuffer();
  268. desc.append('(');
  269. if (paramTypes != null) {
  270. int n = paramTypes.length;
  271. for (int i = 0; i < n; ++i)
  272. toDescriptor(desc, paramTypes[i]);
  273. }
  274. desc.append(')');
  275. if (returnType != null)
  276. toDescriptor(desc, returnType);
  277. return desc.toString();
  278. }
  279. /**
  280. * Returns the descriptor representing a list of parameter types.
  281. * For example, if the given parameter types are two <code>int</code>,
  282. * then this method returns <code>"(II)"</code>.
  283. *
  284. * @param paramTypes parameter types
  285. */
  286. public static String ofParameters(CtClass[] paramTypes) {
  287. return ofMethod(null, paramTypes);
  288. }
  289. /**
  290. * Appends a parameter type to the parameter list represented
  291. * by the given descriptor.
  292. *
  293. * <p><code>classname</code> must not be an array type.
  294. *
  295. * @param classname parameter type (not primitive type)
  296. * @param desc descriptor
  297. */
  298. public static String appendParameter(String classname, String desc) {
  299. int i = desc.indexOf(')');
  300. if (i < 0)
  301. return desc;
  302. else {
  303. StringBuffer newdesc = new StringBuffer();
  304. newdesc.append(desc.substring(0, i));
  305. newdesc.append('L');
  306. newdesc.append(classname.replace('.', '/'));
  307. newdesc.append(';');
  308. newdesc.append(desc.substring(i));
  309. return newdesc.toString();
  310. }
  311. }
  312. /**
  313. * Inserts a parameter type at the beginning of the parameter
  314. * list represented
  315. * by the given descriptor.
  316. *
  317. * <p><code>classname</code> must not be an array type.
  318. *
  319. * @param classname parameter type (not primitive type)
  320. * @param desc descriptor
  321. */
  322. public static String insertParameter(String classname, String desc) {
  323. if (desc.charAt(0) != '(')
  324. return desc;
  325. else
  326. return "(L" + classname.replace('.', '/') + ';'
  327. + desc.substring(1);
  328. }
  329. /**
  330. * Appends a parameter type to the parameter list represented
  331. * by the given descriptor. The appended parameter becomes
  332. * the last parameter.
  333. *
  334. * @param type the type of the appended parameter.
  335. * @param descriptor the original descriptor.
  336. */
  337. public static String appendParameter(CtClass type, String descriptor) {
  338. int i = descriptor.indexOf(')');
  339. if (i < 0)
  340. return descriptor;
  341. else {
  342. StringBuffer newdesc = new StringBuffer();
  343. newdesc.append(descriptor.substring(0, i));
  344. toDescriptor(newdesc, type);
  345. newdesc.append(descriptor.substring(i));
  346. return newdesc.toString();
  347. }
  348. }
  349. /**
  350. * Inserts a parameter type at the beginning of the parameter
  351. * list represented
  352. * by the given descriptor.
  353. *
  354. * @param type the type of the inserted parameter.
  355. * @param descriptor the descriptor of the method.
  356. */
  357. public static String insertParameter(CtClass type,
  358. String descriptor) {
  359. if (descriptor.charAt(0) != '(')
  360. return descriptor;
  361. else
  362. return "(" + of(type) + descriptor.substring(1);
  363. }
  364. /**
  365. * Changes the return type included in the given descriptor.
  366. *
  367. * <p><code>classname</code> must not be an array type.
  368. *
  369. * @param classname return type
  370. * @param desc descriptor
  371. */
  372. public static String changeReturnType(String classname, String desc) {
  373. int i = desc.indexOf(')');
  374. if (i < 0)
  375. return desc;
  376. else {
  377. StringBuffer newdesc = new StringBuffer();
  378. newdesc.append(desc.substring(0, i + 1));
  379. newdesc.append('L');
  380. newdesc.append(classname.replace('.', '/'));
  381. newdesc.append(';');
  382. return newdesc.toString();
  383. }
  384. }
  385. /**
  386. * Returns the <code>CtClass</code> objects representing the parameter
  387. * types specified by the given descriptor.
  388. *
  389. * @param desc descriptor
  390. * @param cp the class pool used for obtaining
  391. * a <code>CtClass</code> object.
  392. */
  393. public static CtClass[] getParameterTypes(String desc, ClassPool cp)
  394. throws NotFoundException
  395. {
  396. if (desc.charAt(0) != '(')
  397. return null;
  398. else {
  399. int num = numOfParameters(desc);
  400. CtClass[] args = new CtClass[num];
  401. int n = 0;
  402. int i = 1;
  403. do {
  404. i = toCtClass(cp, desc, i, args, n++);
  405. } while (i > 0);
  406. return args;
  407. }
  408. }
  409. /**
  410. * Returns true if the list of the parameter types of desc1 is equal to
  411. * that of desc2.
  412. * For example, "(II)V" and "(II)I" are equal.
  413. */
  414. public static boolean eqParamTypes(String desc1, String desc2) {
  415. if (desc1.charAt(0) != '(')
  416. return false;
  417. for (int i = 0; true; ++i) {
  418. char c = desc1.charAt(i);
  419. if (c != desc2.charAt(i))
  420. return false;
  421. if (c == ')')
  422. return true;
  423. }
  424. }
  425. /**
  426. * Returns the signature of the given descriptor. The signature does
  427. * not include the return type. For example, the signature of "(I)V"
  428. * is "(I)".
  429. */
  430. public static String getParamDescriptor(String decl) {
  431. return decl.substring(0, decl.indexOf(')') + 1);
  432. }
  433. /**
  434. * Returns the <code>CtClass</code> object representing the return
  435. * type specified by the given descriptor.
  436. *
  437. * @param desc descriptor
  438. * @param cp the class pool used for obtaining
  439. * a <code>CtClass</code> object.
  440. */
  441. public static CtClass getReturnType(String desc, ClassPool cp)
  442. throws NotFoundException
  443. {
  444. int i = desc.indexOf(')');
  445. if (i < 0)
  446. return null;
  447. else {
  448. CtClass[] type = new CtClass[1];
  449. toCtClass(cp, desc, i + 1, type, 0);
  450. return type[0];
  451. }
  452. }
  453. /**
  454. * Returns the number of the prameters included in the given
  455. * descriptor.
  456. *
  457. * @param desc descriptor
  458. */
  459. public static int numOfParameters(String desc) {
  460. int n = 0;
  461. int i = 1;
  462. for (;;) {
  463. char c = desc.charAt(i);
  464. if (c == ')')
  465. break;
  466. while (c == '[')
  467. c = desc.charAt(++i);
  468. if (c == 'L') {
  469. i = desc.indexOf(';', i) + 1;
  470. if (i <= 0)
  471. throw new IndexOutOfBoundsException("bad descriptor");
  472. }
  473. else
  474. ++i;
  475. ++n;
  476. }
  477. return n;
  478. }
  479. /**
  480. * Returns a <code>CtClass</code> object representing the type
  481. * specified by the given descriptor.
  482. *
  483. * <p>This method works even if the package-class separator is
  484. * not <code>/</code> but <code>.</code> (period). For example,
  485. * it accepts <code>Ljava.lang.Object;</code>
  486. * as well as <code>Ljava/lang/Object;</code>.
  487. *
  488. * @param desc descriptor.
  489. * @param cp the class pool used for obtaining
  490. * a <code>CtClass</code> object.
  491. */
  492. public static CtClass toCtClass(String desc, ClassPool cp)
  493. throws NotFoundException
  494. {
  495. CtClass[] clazz = new CtClass[1];
  496. int res = toCtClass(cp, desc, 0, clazz, 0);
  497. if (res >= 0)
  498. return clazz[0];
  499. else {
  500. // maybe, you forgot to surround the class name with
  501. // L and ;. It violates the protocol, but I'm tolerant...
  502. return cp.get(desc.replace('/', '.'));
  503. }
  504. }
  505. private static int toCtClass(ClassPool cp, String desc, int i,
  506. CtClass[] args, int n)
  507. throws NotFoundException
  508. {
  509. int i2;
  510. String name;
  511. int arrayDim = 0;
  512. char c = desc.charAt(i);
  513. while (c == '[') {
  514. ++arrayDim;
  515. c = desc.charAt(++i);
  516. }
  517. if (c == 'L') {
  518. i2 = desc.indexOf(';', ++i);
  519. name = desc.substring(i, i2++).replace('/', '.');
  520. }
  521. else {
  522. CtClass type = toPrimitiveClass(c);
  523. if (type == null)
  524. return -1; // error
  525. i2 = i + 1;
  526. if (arrayDim == 0) {
  527. args[n] = type;
  528. return i2; // neither an array type or a class type
  529. }
  530. else
  531. name = type.getName();
  532. }
  533. if (arrayDim > 0) {
  534. StringBuffer sbuf = new StringBuffer(name);
  535. while (arrayDim-- > 0)
  536. sbuf.append("[]");
  537. name = sbuf.toString();
  538. }
  539. args[n] = cp.get(name);
  540. return i2;
  541. }
  542. static CtClass toPrimitiveClass(char c) {
  543. CtClass type = null;
  544. switch (c) {
  545. case 'Z' :
  546. type = CtClass.booleanType;
  547. break;
  548. case 'C' :
  549. type = CtClass.charType;
  550. break;
  551. case 'B' :
  552. type = CtClass.byteType;
  553. break;
  554. case 'S' :
  555. type = CtClass.shortType;
  556. break;
  557. case 'I' :
  558. type = CtClass.intType;
  559. break;
  560. case 'J' :
  561. type = CtClass.longType;
  562. break;
  563. case 'F' :
  564. type = CtClass.floatType;
  565. break;
  566. case 'D' :
  567. type = CtClass.doubleType;
  568. break;
  569. case 'V' :
  570. type = CtClass.voidType;
  571. break;
  572. }
  573. return type;
  574. }
  575. /**
  576. * Computes the dimension of the array represented by the given
  577. * descriptor. For example, if the descriptor is <code>"[[I"</code>,
  578. * then this method returns 2.
  579. *
  580. * @param desc the descriptor.
  581. * @return 0 if the descriptor does not represent an array type.
  582. */
  583. public static int arrayDimension(String desc) {
  584. int dim = 0;
  585. while (desc.charAt(dim) == '[')
  586. ++dim;
  587. return dim;
  588. }
  589. /**
  590. * Returns the descriptor of the type of the array component.
  591. * For example, if the given descriptor is
  592. * <code>"[[Ljava/lang/String;"</code> and the given dimension is 2,
  593. * then this method returns <code>"Ljava/lang/String;"</code>.
  594. *
  595. * @param desc the descriptor.
  596. * @param dim the array dimension.
  597. */
  598. public static String toArrayComponent(String desc, int dim) {
  599. return desc.substring(dim);
  600. }
  601. /**
  602. * Computes the data size specified by the given descriptor.
  603. * For example, if the descriptor is "D", this method returns 2.
  604. *
  605. * <p>If the descriptor represents a method type, this method returns
  606. * (the size of the returned value) - (the sum of the data sizes
  607. * of all the parameters). For example, if the descriptor is
  608. * <code>"(I)D"</code>, then this method returns 1 (= 2 - 1).
  609. *
  610. * @param desc descriptor
  611. */
  612. public static int dataSize(String desc) {
  613. return dataSize(desc, true);
  614. }
  615. /**
  616. * Computes the data size of parameters.
  617. * If one of the parameters is double type, the size of that parameter
  618. * is 2 words. For example, if the given descriptor is
  619. * <code>"(IJ)D"</code>, then this method returns 3. The size of the
  620. * return type is not computed.
  621. *
  622. * @param desc a method descriptor.
  623. */
  624. public static int paramSize(String desc) {
  625. return -dataSize(desc, false);
  626. }
  627. private static int dataSize(String desc, boolean withRet) {
  628. int n = 0;
  629. char c = desc.charAt(0);
  630. if (c == '(') {
  631. int i = 1;
  632. for (;;) {
  633. c = desc.charAt(i);
  634. if (c == ')') {
  635. c = desc.charAt(i + 1);
  636. break;
  637. }
  638. boolean array = false;
  639. while (c == '[') {
  640. array = true;
  641. c = desc.charAt(++i);
  642. }
  643. if (c == 'L') {
  644. i = desc.indexOf(';', i) + 1;
  645. if (i <= 0)
  646. throw new IndexOutOfBoundsException("bad descriptor");
  647. }
  648. else
  649. ++i;
  650. if (!array && (c == 'J' || c == 'D'))
  651. n -= 2;
  652. else
  653. --n;
  654. }
  655. }
  656. if (withRet)
  657. if (c == 'J' || c == 'D')
  658. n += 2;
  659. else if (c != 'V')
  660. ++n;
  661. return n;
  662. }
  663. /**
  664. * Returns a human-readable representation of the
  665. * given descriptor. For example, <code>Ljava/lang/Object;</code>
  666. * is converted into <code>java.lang.Object</code>.
  667. * <code>(I[I)V</code> is converted into <code>(int, int[])</code>
  668. * (the return type is ignored).
  669. */
  670. public static String toString(String desc) {
  671. return PrettyPrinter.toString(desc);
  672. }
  673. static class PrettyPrinter {
  674. static String toString(String desc) {
  675. StringBuffer sbuf = new StringBuffer();
  676. if (desc.charAt(0) == '(') {
  677. int pos = 1;
  678. sbuf.append('(');
  679. while (desc.charAt(pos) != ')') {
  680. if (pos > 1)
  681. sbuf.append(',');
  682. pos = readType(sbuf, pos, desc);
  683. }
  684. sbuf.append(')');
  685. }
  686. else
  687. readType(sbuf, 0, desc);
  688. return sbuf.toString();
  689. }
  690. static int readType(StringBuffer sbuf, int pos, String desc) {
  691. char c = desc.charAt(pos);
  692. int arrayDim = 0;
  693. while (c == '[') {
  694. arrayDim++;
  695. c = desc.charAt(++pos);
  696. }
  697. if (c == 'L')
  698. while (true) {
  699. c = desc.charAt(++pos);
  700. if (c == ';')
  701. break;
  702. if (c == '/')
  703. c = '.';
  704. sbuf.append(c);
  705. }
  706. else {
  707. CtClass t = toPrimitiveClass(c);
  708. sbuf.append(t.getName());
  709. }
  710. while (arrayDim-- > 0)
  711. sbuf.append("[]");
  712. return pos + 1;
  713. }
  714. }
  715. /**
  716. * An Iterator over a descriptor.
  717. */
  718. public static class Iterator {
  719. private String desc;
  720. private int index, curPos;
  721. private boolean param;
  722. /**
  723. * Constructs an iterator.
  724. *
  725. * @param s descriptor.
  726. */
  727. public Iterator(String s) {
  728. desc = s;
  729. index = curPos = 0;
  730. param = false;
  731. }
  732. /**
  733. * Returns true if the iteration has more elements.
  734. */
  735. public boolean hasNext() {
  736. return index < desc.length();
  737. }
  738. /**
  739. * Returns true if the current element is a parameter type.
  740. */
  741. public boolean isParameter() { return param; }
  742. /**
  743. * Returns the first character of the current element.
  744. */
  745. public char currentChar() { return desc.charAt(curPos); }
  746. /**
  747. * Returns true if the current element is double or long type.
  748. */
  749. public boolean is2byte() {
  750. char c = currentChar();
  751. return c == 'D' || c == 'J';
  752. }
  753. /**
  754. * Returns the position of the next type character.
  755. * That type character becomes a new current element.
  756. */
  757. public int next() {
  758. int nextPos = index;
  759. char c = desc.charAt(nextPos);
  760. if (c == '(') {
  761. ++index;
  762. c = desc.charAt(++nextPos);
  763. param = true;
  764. }
  765. if (c == ')') {
  766. ++index;
  767. c = desc.charAt(++nextPos);
  768. param = false;
  769. }
  770. while (c == '[')
  771. c = desc.charAt(++nextPos);
  772. if (c == 'L') {
  773. nextPos = desc.indexOf(';', nextPos) + 1;
  774. if (nextPos <= 0)
  775. throw new IndexOutOfBoundsException("bad descriptor");
  776. }
  777. else
  778. ++nextPos;
  779. curPos = index;
  780. index = nextPos;
  781. return curPos;
  782. }
  783. }
  784. }