Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

Descriptor.java 24KB

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