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 17 package javassist.bytecode; 18 19 import java.io.DataInputStream; 20 import java.io.IOException; 21 import java.util.ArrayList; 22 import java.util.HashMap; 23 import java.util.List; 24 import java.util.Map; 25 26 import javassist.CtClass; 27 28 /** 29 * <code>Signature_attribute</code>. 30 */ 31 public class SignatureAttribute extends AttributeInfo { 32 /** 33 * The name of this attribute <code>"Signature"</code>. 34 */ 35 public static final String tag = "Signature"; 36 SignatureAttribute(ConstPool cp, int n, DataInputStream in)37 SignatureAttribute(ConstPool cp, int n, DataInputStream in) 38 throws IOException 39 { 40 super(cp, n, in); 41 } 42 43 /** 44 * Constructs a <code>Signature</code> attribute. 45 * 46 * @param cp a constant pool table. 47 * @param signature the signature represented by this attribute. 48 */ SignatureAttribute(ConstPool cp, String signature)49 public SignatureAttribute(ConstPool cp, String signature) { 50 super(cp, tag); 51 int index = cp.addUtf8Info(signature); 52 byte[] bvalue = new byte[2]; 53 bvalue[0] = (byte)(index >>> 8); 54 bvalue[1] = (byte)index; 55 set(bvalue); 56 } 57 58 /** 59 * Returns the generic signature indicated by <code>signature_index</code>. 60 * 61 * @see #toClassSignature(String) 62 * @see #toMethodSignature(String) 63 * @see #toFieldSignature(String) 64 */ getSignature()65 public String getSignature() { 66 return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); 67 } 68 69 /** 70 * Sets <code>signature_index</code> to the index of the given generic signature, 71 * which is added to a constant pool. 72 * 73 * @param sig new signature. 74 * @since 3.11 75 */ setSignature(String sig)76 public void setSignature(String sig) { 77 int index = getConstPool().addUtf8Info(sig); 78 ByteArray.write16bit(index, info, 0); 79 } 80 81 /** 82 * Makes a copy. Class names are replaced according to the 83 * given <code>Map</code> object. 84 * 85 * @param newCp the constant pool table used by the new copy. 86 * @param classnames pairs of replaced and substituted 87 * class names. 88 */ 89 @Override copy(ConstPool newCp, Map<String,String> classnames)90 public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames) { 91 return new SignatureAttribute(newCp, getSignature()); 92 } 93 94 @Override renameClass(String oldname, String newname)95 void renameClass(String oldname, String newname) { 96 String sig = renameClass(getSignature(), oldname, newname); 97 setSignature(sig); 98 } 99 100 @Override renameClass(Map<String,String> classnames)101 void renameClass(Map<String,String> classnames) { 102 String sig = renameClass(getSignature(), classnames); 103 setSignature(sig); 104 } 105 renameClass(String desc, String oldname, String newname)106 static String renameClass(String desc, String oldname, String newname) { 107 Map<String,String> map = new HashMap<String,String>(); 108 map.put(oldname, newname); 109 return renameClass(desc, map); 110 } 111 renameClass(String desc, Map<String,String> map)112 static String renameClass(String desc, Map<String,String> map) { 113 if (map == null) 114 return desc; 115 116 StringBuilder newdesc = new StringBuilder(); 117 int head = 0; 118 int i = 0; 119 for (;;) { 120 int j = desc.indexOf('L', i); 121 if (j < 0) 122 break; 123 124 StringBuilder nameBuf = new StringBuilder(); 125 int k = j; 126 char c; 127 try { 128 while ((c = desc.charAt(++k)) != ';') { 129 nameBuf.append(c); 130 if (c == '<') { 131 while ((c = desc.charAt(++k)) != '>') 132 nameBuf.append(c); 133 134 nameBuf.append(c); 135 } 136 } 137 } 138 catch (IndexOutOfBoundsException e) { break; } 139 i = k + 1; 140 String name = nameBuf.toString(); 141 String name2 = map.get(name); 142 if (name2 != null) { 143 newdesc.append(desc.substring(head, j)); 144 newdesc.append('L'); 145 newdesc.append(name2); 146 newdesc.append(c); 147 head = i; 148 } 149 } 150 151 if (head == 0) 152 return desc; 153 int len = desc.length(); 154 if (head < len) 155 newdesc.append(desc.substring(head, len)); 156 157 return newdesc.toString(); 158 } 159 160 @SuppressWarnings("unused") isNamePart(int c)161 private static boolean isNamePart(int c) { 162 return c != ';' && c != '<'; 163 } 164 165 static private class Cursor { 166 int position = 0; 167 indexOf(String s, int ch)168 int indexOf(String s, int ch) throws BadBytecode { 169 int i = s.indexOf(ch, position); 170 if (i < 0) 171 throw error(s); 172 position = i + 1; 173 return i; 174 } 175 } 176 177 /** 178 * Class signature. 179 */ 180 public static class ClassSignature { 181 TypeParameter[] params; 182 ClassType superClass; 183 ClassType[] interfaces; 184 185 /** 186 * Constructs a class signature. 187 * 188 * @param params type parameters. 189 * @param superClass the super class. 190 * @param interfaces the interface types. 191 */ ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces)192 public ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces) { 193 this.params = params == null ? new TypeParameter[0] : params; 194 this.superClass = superClass == null ? ClassType.OBJECT : superClass; 195 this.interfaces = interfaces == null ? new ClassType[0] : interfaces; 196 } 197 198 /** 199 * Constructs a class signature. 200 * 201 * @param p type parameters. 202 */ ClassSignature(TypeParameter[] p)203 public ClassSignature(TypeParameter[] p) { 204 this(p, null, null); 205 } 206 207 /** 208 * Returns the type parameters. 209 * 210 * @return a zero-length array if the type parameters are not specified. 211 */ getParameters()212 public TypeParameter[] getParameters() { 213 return params; 214 } 215 216 /** 217 * Returns the super class. 218 */ getSuperClass()219 public ClassType getSuperClass() { return superClass; } 220 221 /** 222 * Returns the super interfaces. 223 * 224 * @return a zero-length array if the super interfaces are not specified. 225 */ getInterfaces()226 public ClassType[] getInterfaces() { return interfaces; } 227 228 /** 229 * Returns the string representation. 230 */ 231 @Override toString()232 public String toString() { 233 StringBuffer sbuf = new StringBuffer(); 234 235 TypeParameter.toString(sbuf, params); 236 sbuf.append(" extends ").append(superClass); 237 if (interfaces.length > 0) { 238 sbuf.append(" implements "); 239 Type.toString(sbuf, interfaces); 240 } 241 242 return sbuf.toString(); 243 } 244 245 /** 246 * Returns the encoded string representing the method type signature. 247 */ encode()248 public String encode() { 249 StringBuffer sbuf = new StringBuffer(); 250 if (params.length > 0) { 251 sbuf.append('<'); 252 for (int i = 0; i < params.length; i++) 253 params[i].encode(sbuf); 254 255 sbuf.append('>'); 256 } 257 258 superClass.encode(sbuf); 259 for (int i = 0; i < interfaces.length; i++) 260 interfaces[i].encode(sbuf); 261 262 return sbuf.toString(); 263 } 264 } 265 266 /** 267 * Method type signature. 268 */ 269 public static class MethodSignature { 270 TypeParameter[] typeParams; 271 Type[] params; 272 Type retType; 273 ObjectType[] exceptions; 274 275 /** 276 * Constructs a method type signature. Any parameter can be null 277 * to represent <code>void</code> or nothing. 278 * 279 * @param tp type parameters. 280 * @param params parameter types. 281 * @param ret a return type, or null if the return type is <code>void</code>. 282 * @param ex exception types. 283 */ MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex)284 public MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex) { 285 typeParams = tp == null ? new TypeParameter[0] : tp; 286 this.params = params == null ? new Type[0] : params; 287 retType = ret == null ? new BaseType("void") : ret; 288 exceptions = ex == null ? new ObjectType[0] : ex; 289 } 290 291 /** 292 * Returns the formal type parameters. 293 * 294 * @return a zero-length array if the type parameters are not specified. 295 */ getTypeParameters()296 public TypeParameter[] getTypeParameters() { return typeParams; } 297 298 /** 299 * Returns the types of the formal parameters. 300 * 301 * @return a zero-length array if no formal parameter is taken. 302 */ getParameterTypes()303 public Type[] getParameterTypes() { return params; } 304 305 /** 306 * Returns the type of the returned value. 307 */ getReturnType()308 public Type getReturnType() { return retType; } 309 310 /** 311 * Returns the types of the exceptions that may be thrown. 312 * 313 * @return a zero-length array if exceptions are never thrown or 314 * the exception types are not parameterized types or type variables. 315 */ getExceptionTypes()316 public ObjectType[] getExceptionTypes() { return exceptions; } 317 318 /** 319 * Returns the string representation. 320 */ 321 @Override toString()322 public String toString() { 323 StringBuffer sbuf = new StringBuffer(); 324 325 TypeParameter.toString(sbuf, typeParams); 326 sbuf.append(" ("); 327 Type.toString(sbuf, params); 328 sbuf.append(") "); 329 sbuf.append(retType); 330 if (exceptions.length > 0) { 331 sbuf.append(" throws "); 332 Type.toString(sbuf, exceptions); 333 } 334 335 return sbuf.toString(); 336 } 337 338 /** 339 * Returns the encoded string representing the method type signature. 340 */ encode()341 public String encode() { 342 StringBuffer sbuf = new StringBuffer(); 343 if (typeParams.length > 0) { 344 sbuf.append('<'); 345 for (int i = 0; i < typeParams.length; i++) 346 typeParams[i].encode(sbuf); 347 348 sbuf.append('>'); 349 } 350 351 sbuf.append('('); 352 for (int i = 0; i < params.length; i++) 353 params[i].encode(sbuf); 354 355 sbuf.append(')'); 356 retType.encode(sbuf); 357 if (exceptions.length > 0) 358 for (int i = 0; i < exceptions.length; i++) { 359 sbuf.append('^'); 360 exceptions[i].encode(sbuf); 361 } 362 363 return sbuf.toString(); 364 } 365 } 366 367 /** 368 * Formal type parameters. 369 * 370 * @see TypeArgument 371 */ 372 public static class TypeParameter { 373 String name; 374 ObjectType superClass; 375 ObjectType[] superInterfaces; 376 TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si)377 TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) { 378 name = sig.substring(nb, ne); 379 superClass = sc; 380 superInterfaces = si; 381 } 382 383 /** 384 * Constructs a <code>TypeParameter</code> representing a type parametre 385 * like <code><T extends ... ></code>. 386 * 387 * @param name parameter name. 388 * @param superClass an upper bound class-type (or null). 389 * @param superInterfaces an upper bound interface-type (or null). 390 */ TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces)391 public TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces) { 392 this.name = name; 393 this.superClass = superClass; 394 if (superInterfaces == null) 395 this.superInterfaces = new ObjectType[0]; 396 else 397 this.superInterfaces = superInterfaces; 398 } 399 400 /** 401 * Constructs a <code>TypeParameter</code> representing a type parameter 402 * like <code><T></code>. 403 * 404 * @param name parameter name. 405 */ TypeParameter(String name)406 public TypeParameter(String name) { 407 this(name, null, null); 408 } 409 410 /** 411 * Returns the name of the type parameter. 412 */ getName()413 public String getName() { 414 return name; 415 } 416 417 /** 418 * Returns the class bound of this parameter. 419 */ getClassBound()420 public ObjectType getClassBound() { return superClass; } 421 422 /** 423 * Returns the interface bound of this parameter. 424 * 425 * @return a zero-length array if the interface bound is not specified. 426 */ getInterfaceBound()427 public ObjectType[] getInterfaceBound() { return superInterfaces; } 428 429 /** 430 * Returns the string representation. 431 */ 432 @Override toString()433 public String toString() { 434 StringBuffer sbuf = new StringBuffer(getName()); 435 if (superClass != null) 436 sbuf.append(" extends ").append(superClass.toString()); 437 438 int len = superInterfaces.length; 439 if (len > 0) { 440 for (int i = 0; i < len; i++) { 441 if (i > 0 || superClass != null) 442 sbuf.append(" & "); 443 else 444 sbuf.append(" extends "); 445 446 sbuf.append(superInterfaces[i].toString()); 447 } 448 } 449 450 return sbuf.toString(); 451 } 452 toString(StringBuffer sbuf, TypeParameter[] tp)453 static void toString(StringBuffer sbuf, TypeParameter[] tp) { 454 sbuf.append('<'); 455 for (int i = 0; i < tp.length; i++) { 456 if (i > 0) 457 sbuf.append(", "); 458 459 sbuf.append(tp[i]); 460 } 461 462 sbuf.append('>'); 463 } 464 encode(StringBuffer sb)465 void encode(StringBuffer sb) { 466 sb.append(name); 467 if (superClass == null) 468 sb.append(":Ljava/lang/Object;"); 469 else { 470 sb.append(':'); 471 superClass.encode(sb); 472 } 473 474 for (int i = 0; i < superInterfaces.length; i++) { 475 sb.append(':'); 476 superInterfaces[i].encode(sb); 477 } 478 } 479 } 480 481 /** 482 * Type argument. 483 * 484 * @see TypeParameter 485 */ 486 public static class TypeArgument { 487 ObjectType arg; 488 char wildcard; 489 TypeArgument(ObjectType a, char w)490 TypeArgument(ObjectType a, char w) { 491 arg = a; 492 wildcard = w; 493 } 494 495 /** 496 * Constructs a <code>TypeArgument</code>. 497 * A type argument is <code><String></code>, <code><int[]></code>, 498 * or a type variable <code><T></code>, etc. 499 * 500 * @param t a class type, an array type, or a type variable. 501 */ TypeArgument(ObjectType t)502 public TypeArgument(ObjectType t) { 503 this(t, ' '); 504 } 505 506 /** 507 * Constructs a <code>TypeArgument</code> representing <code><?></code>. 508 */ TypeArgument()509 public TypeArgument() { 510 this(null, '*'); 511 } 512 513 /** 514 * A factory method constructing a <code>TypeArgument</code> with an upper bound. 515 * It represents <code><? extends ... ></code> 516 * 517 * @param t an upper bound type. 518 */ subclassOf(ObjectType t)519 public static TypeArgument subclassOf(ObjectType t) { 520 return new TypeArgument(t, '+'); 521 } 522 523 /** 524 * A factory method constructing a <code>TypeArgument</code> with an lower bound. 525 * It represents <code><? super ... ></code> 526 * 527 * @param t an lower bbound type. 528 */ superOf(ObjectType t)529 public static TypeArgument superOf(ObjectType t) { 530 return new TypeArgument(t, '-'); 531 } 532 533 /** 534 * Returns the kind of this type argument. 535 * 536 * @return <code>' '</code> (not-wildcard), <code>'*'</code> (wildcard), <code>'+'</code> (wildcard with 537 * upper bound), or <code>'-'</code> (wildcard with lower bound). 538 */ getKind()539 public char getKind() { return wildcard; } 540 541 /** 542 * Returns true if this type argument is a wildcard type 543 * such as <code>?</code>, <code>? extends String</code>, or <code>? super Integer</code>. 544 */ isWildcard()545 public boolean isWildcard() { return wildcard != ' '; } 546 547 /** 548 * Returns the type represented by this argument 549 * if the argument is not a wildcard type. Otherwise, this method 550 * returns the upper bound (if the kind is '+'), 551 * the lower bound (if the kind is '-'), or null (if the upper or lower 552 * bound is not specified). 553 */ getType()554 public ObjectType getType() { return arg; } 555 556 /** 557 * Returns the string representation. 558 */ 559 @Override toString()560 public String toString() { 561 if (wildcard == '*') 562 return "?"; 563 564 String type = arg.toString(); 565 if (wildcard == ' ') 566 return type; 567 else if (wildcard == '+') 568 return "? extends " + type; 569 else 570 return "? super " + type; 571 } 572 encode(StringBuffer sb, TypeArgument[] args)573 static void encode(StringBuffer sb, TypeArgument[] args) { 574 sb.append('<'); 575 for (int i = 0; i < args.length; i++) { 576 TypeArgument ta = args[i]; 577 if (ta.isWildcard()) 578 sb.append(ta.wildcard); 579 580 if (ta.getType() != null) 581 ta.getType().encode(sb); 582 } 583 584 sb.append('>'); 585 } 586 } 587 588 /** 589 * Primitive types and object types. 590 */ 591 public static abstract class Type { encode(StringBuffer sb)592 abstract void encode(StringBuffer sb); toString(StringBuffer sbuf, Type[] ts)593 static void toString(StringBuffer sbuf, Type[] ts) { 594 for (int i = 0; i < ts.length; i++) { 595 if (i > 0) 596 sbuf.append(", "); 597 598 sbuf.append(ts[i]); 599 } 600 } 601 602 /** 603 * Returns the type name in the JVM internal style. 604 * For example, if the type is a nested class {@code foo.Bar.Baz}, 605 * then {@code foo.Bar$Baz} is returned. 606 */ jvmTypeName()607 public String jvmTypeName() { return toString(); } 608 } 609 610 /** 611 * Primitive types. 612 */ 613 public static class BaseType extends Type { 614 char descriptor; BaseType(char c)615 BaseType(char c) { descriptor = c; } 616 617 /** 618 * Constructs a <code>BaseType</code>. 619 * 620 * @param typeName <code>void</code>, <code>int</code>, ... 621 */ BaseType(String typeName)622 public BaseType(String typeName) { 623 this(Descriptor.of(typeName).charAt(0)); 624 } 625 626 /** 627 * Returns the descriptor representing this primitive type. 628 * 629 * @see javassist.bytecode.Descriptor 630 */ getDescriptor()631 public char getDescriptor() { return descriptor; } 632 633 /** 634 * Returns the <code>CtClass</code> representing this 635 * primitive type. 636 */ getCtlass()637 public CtClass getCtlass() { 638 return Descriptor.toPrimitiveClass(descriptor); 639 } 640 641 /** 642 * Returns the string representation. 643 */ 644 @Override toString()645 public String toString() { 646 return Descriptor.toClassName(Character.toString(descriptor)); 647 } 648 649 @Override encode(StringBuffer sb)650 void encode(StringBuffer sb) { 651 sb.append(descriptor); 652 } 653 } 654 655 /** 656 * Class types, array types, and type variables. 657 * This class is also used for representing a field type. 658 */ 659 public static abstract class ObjectType extends Type { 660 /** 661 * Returns the encoded string representing the object type signature. 662 */ encode()663 public String encode() { 664 StringBuffer sb = new StringBuffer(); 665 encode(sb); 666 return sb.toString(); 667 } 668 } 669 670 /** 671 * Class types. 672 */ 673 public static class ClassType extends ObjectType { 674 String name; 675 TypeArgument[] arguments; 676 make(String s, int b, int e, TypeArgument[] targs, ClassType parent)677 static ClassType make(String s, int b, int e, 678 TypeArgument[] targs, ClassType parent) { 679 if (parent == null) 680 return new ClassType(s, b, e, targs); 681 return new NestedClassType(s, b, e, targs, parent); 682 } 683 ClassType(String signature, int begin, int end, TypeArgument[] targs)684 ClassType(String signature, int begin, int end, TypeArgument[] targs) { 685 name = signature.substring(begin, end).replace('/', '.'); 686 arguments = targs; 687 } 688 689 /** 690 * A class type representing <code>java.lang.Object</code>. 691 */ 692 public static ClassType OBJECT = new ClassType("java.lang.Object", null); 693 694 /** 695 * Constructs a <code>ClassType</code>. It represents 696 * the name of a non-nested class. 697 * 698 * @param className a fully qualified class name. 699 * @param args type arguments or null. 700 */ ClassType(String className, TypeArgument[] args)701 public ClassType(String className, TypeArgument[] args) { 702 name = className; 703 arguments = args; 704 } 705 706 /** 707 * Constructs a <code>ClassType</code>. It represents 708 * the name of a non-nested class. 709 * 710 * @param className a fully qualified class name. 711 */ ClassType(String className)712 public ClassType(String className) { 713 this(className, null); 714 } 715 716 /** 717 * Returns the class name. 718 */ getName()719 public String getName() { 720 return name; 721 } 722 723 /** 724 * Returns the type arguments. 725 * 726 * @return null if no type arguments are given to this class. 727 */ getTypeArguments()728 public TypeArgument[] getTypeArguments() { return arguments; } 729 730 /** 731 * If this class is a member of another class, returns the 732 * class in which this class is declared. 733 * 734 * @return null if this class is not a member of another class. 735 */ getDeclaringClass()736 public ClassType getDeclaringClass() { return null; } 737 738 /** 739 * Returns the string representation. 740 */ 741 @Override toString()742 public String toString() { 743 StringBuffer sbuf = new StringBuffer(); 744 ClassType parent = getDeclaringClass(); 745 if (parent != null) 746 sbuf.append(parent.toString()).append('.'); 747 748 return toString2(sbuf); 749 } 750 toString2(StringBuffer sbuf)751 private String toString2(StringBuffer sbuf) { 752 sbuf.append(name); 753 if (arguments != null) { 754 sbuf.append('<'); 755 int n = arguments.length; 756 for (int i = 0; i < n; i++) { 757 if (i > 0) 758 sbuf.append(", "); 759 760 sbuf.append(arguments[i].toString()); 761 } 762 763 sbuf.append('>'); 764 } 765 766 return sbuf.toString(); 767 } 768 769 /** 770 * Returns the type name in the JVM internal style. 771 * For example, if the type is a nested class {@code foo.Bar.Baz}, 772 * then {@code foo.Bar$Baz} is returned. 773 */ 774 @Override jvmTypeName()775 public String jvmTypeName() { 776 StringBuffer sbuf = new StringBuffer(); 777 ClassType parent = getDeclaringClass(); 778 if (parent != null) 779 sbuf.append(parent.jvmTypeName()).append('$'); 780 781 return toString2(sbuf); 782 } 783 784 @Override encode(StringBuffer sb)785 void encode(StringBuffer sb) { 786 sb.append('L'); 787 encode2(sb); 788 sb.append(';'); 789 } 790 encode2(StringBuffer sb)791 void encode2(StringBuffer sb) { 792 ClassType parent = getDeclaringClass(); 793 if (parent != null) { 794 parent.encode2(sb); 795 sb.append('$'); 796 } 797 798 sb.append(name.replace('.', '/')); 799 if (arguments != null) 800 TypeArgument.encode(sb, arguments); 801 } 802 } 803 804 /** 805 * Nested class types. 806 */ 807 public static class NestedClassType extends ClassType { 808 ClassType parent; NestedClassType(String s, int b, int e, TypeArgument[] targs, ClassType p)809 NestedClassType(String s, int b, int e, 810 TypeArgument[] targs, ClassType p) { 811 super(s, b, e, targs); 812 parent = p; 813 } 814 815 /** 816 * Constructs a <code>NestedClassType</code>. 817 * 818 * @param parent the class surrounding this class type. 819 * @param className a simple class name. It does not include 820 * a package name or a parent's class name. 821 * @param args type parameters or null. 822 */ NestedClassType(ClassType parent, String className, TypeArgument[] args)823 public NestedClassType(ClassType parent, String className, TypeArgument[] args) { 824 super(className, args); 825 this.parent = parent; 826 } 827 828 /** 829 * Returns the class that declares this nested class. 830 * This nested class is a member of that declaring class. 831 */ 832 @Override getDeclaringClass()833 public ClassType getDeclaringClass() { return parent; } 834 } 835 836 /** 837 * Array types. 838 */ 839 public static class ArrayType extends ObjectType { 840 int dim; 841 Type componentType; 842 843 /** 844 * Constructs an <code>ArrayType</code>. 845 * 846 * @param d dimension. 847 * @param comp the component type. 848 */ ArrayType(int d, Type comp)849 public ArrayType(int d, Type comp) { 850 dim = d; 851 componentType = comp; 852 } 853 854 /** 855 * Returns the dimension of the array. 856 */ getDimension()857 public int getDimension() { return dim; } 858 859 /** 860 * Returns the component type. 861 */ getComponentType()862 public Type getComponentType() { 863 return componentType; 864 } 865 866 /** 867 * Returns the string representation. 868 */ 869 @Override toString()870 public String toString() { 871 StringBuffer sbuf = new StringBuffer(componentType.toString()); 872 for (int i = 0; i < dim; i++) 873 sbuf.append("[]"); 874 875 return sbuf.toString(); 876 } 877 878 @Override encode(StringBuffer sb)879 void encode(StringBuffer sb) { 880 for (int i = 0; i < dim; i++) 881 sb.append('['); 882 883 componentType.encode(sb); 884 } 885 } 886 887 /** 888 * Type variables. 889 */ 890 public static class TypeVariable extends ObjectType { 891 String name; 892 TypeVariable(String sig, int begin, int end)893 TypeVariable(String sig, int begin, int end) { 894 name = sig.substring(begin, end); 895 } 896 897 /** 898 * Constructs a <code>TypeVariable</code>. 899 * 900 * @param name the name of a type variable. 901 */ TypeVariable(String name)902 public TypeVariable(String name) { 903 this.name = name; 904 } 905 906 /** 907 * Returns the variable name. 908 */ getName()909 public String getName() { 910 return name; 911 } 912 913 /** 914 * Returns the string representation. 915 */ 916 @Override toString()917 public String toString() { 918 return name; 919 } 920 921 @Override encode(StringBuffer sb)922 void encode(StringBuffer sb) { 923 sb.append('T').append(name).append(';'); 924 } 925 } 926 927 /** 928 * Parses the given signature string as a class signature. 929 * 930 * @param sig the signature obtained from the <code>SignatureAttribute</code> 931 * of a <code>ClassFile</code>. 932 * @return a tree-like data structure representing a class signature. It provides 933 * convenient accessor methods. 934 * @throws BadBytecode thrown when a syntactical error is found. 935 * @see #getSignature() 936 * @since 3.5 937 */ toClassSignature(String sig)938 public static ClassSignature toClassSignature(String sig) throws BadBytecode { 939 try { 940 return parseSig(sig); 941 } 942 catch (IndexOutOfBoundsException e) { 943 throw error(sig); 944 } 945 } 946 947 /** 948 * Parses the given signature string as a method type signature. 949 * 950 * @param sig the signature obtained from the <code>SignatureAttribute</code> 951 * of a <code>MethodInfo</code>. 952 * @return @return a tree-like data structure representing a method signature. It provides 953 * convenient accessor methods. 954 * @throws BadBytecode thrown when a syntactical error is found. 955 * @see #getSignature() 956 * @since 3.5 957 */ toMethodSignature(String sig)958 public static MethodSignature toMethodSignature(String sig) throws BadBytecode { 959 try { 960 return parseMethodSig(sig); 961 } 962 catch (IndexOutOfBoundsException e) { 963 throw error(sig); 964 } 965 } 966 967 /** 968 * Parses the given signature string as a field type signature. 969 * 970 * @param sig the signature string obtained from the <code>SignatureAttribute</code> 971 * of a <code>FieldInfo</code>. 972 * @return the field type signature. 973 * @throws BadBytecode thrown when a syntactical error is found. 974 * @see #getSignature() 975 * @since 3.5 976 */ toFieldSignature(String sig)977 public static ObjectType toFieldSignature(String sig) throws BadBytecode { 978 try { 979 return parseObjectType(sig, new Cursor(), false); 980 } 981 catch (IndexOutOfBoundsException e) { 982 throw error(sig); 983 } 984 } 985 986 /** 987 * Parses the given signature string as a type signature. 988 * The type signature is either the field type signature or a base type 989 * descriptor including <code>void</code> type. 990 * 991 * @throws BadBytecode thrown when a syntactical error is found. 992 * @since 3.18 993 */ toTypeSignature(String sig)994 public static Type toTypeSignature(String sig) throws BadBytecode { 995 try { 996 return parseType(sig, new Cursor()); 997 } 998 catch (IndexOutOfBoundsException e) { 999 throw error(sig); 1000 } 1001 } 1002 parseSig(String sig)1003 private static ClassSignature parseSig(String sig) 1004 throws BadBytecode, IndexOutOfBoundsException 1005 { 1006 Cursor cur = new Cursor(); 1007 TypeParameter[] tp = parseTypeParams(sig, cur); 1008 ClassType superClass = parseClassType(sig, cur); 1009 int sigLen = sig.length(); 1010 List<ClassType> ifArray = new ArrayList<ClassType>(); 1011 while (cur.position < sigLen && sig.charAt(cur.position) == 'L') 1012 ifArray.add(parseClassType(sig, cur)); 1013 1014 ClassType[] ifs 1015 = ifArray.toArray(new ClassType[ifArray.size()]); 1016 return new ClassSignature(tp, superClass, ifs); 1017 } 1018 parseMethodSig(String sig)1019 private static MethodSignature parseMethodSig(String sig) 1020 throws BadBytecode 1021 { 1022 Cursor cur = new Cursor(); 1023 TypeParameter[] tp = parseTypeParams(sig, cur); 1024 if (sig.charAt(cur.position++) != '(') 1025 throw error(sig); 1026 1027 List<Type> params = new ArrayList<Type>(); 1028 while (sig.charAt(cur.position) != ')') { 1029 Type t = parseType(sig, cur); 1030 params.add(t); 1031 } 1032 1033 cur.position++; 1034 Type ret = parseType(sig, cur); 1035 int sigLen = sig.length(); 1036 List<ObjectType> exceptions = new ArrayList<ObjectType>(); 1037 while (cur.position < sigLen && sig.charAt(cur.position) == '^') { 1038 cur.position++; 1039 ObjectType t = parseObjectType(sig, cur, false); 1040 if (t instanceof ArrayType) 1041 throw error(sig); 1042 1043 exceptions.add(t); 1044 } 1045 1046 Type[] p = params.toArray(new Type[params.size()]); 1047 ObjectType[] ex = exceptions.toArray(new ObjectType[exceptions.size()]); 1048 return new MethodSignature(tp, p, ret, ex); 1049 } 1050 parseTypeParams(String sig, Cursor cur)1051 private static TypeParameter[] parseTypeParams(String sig, Cursor cur) 1052 throws BadBytecode 1053 { 1054 List<TypeParameter> typeParam = new ArrayList<TypeParameter>(); 1055 if (sig.charAt(cur.position) == '<') { 1056 cur.position++; 1057 while (sig.charAt(cur.position) != '>') { 1058 int nameBegin = cur.position; 1059 int nameEnd = cur.indexOf(sig, ':'); 1060 ObjectType classBound = parseObjectType(sig, cur, true); 1061 List<ObjectType> ifBound = new ArrayList<ObjectType>(); 1062 while (sig.charAt(cur.position) == ':') { 1063 cur.position++; 1064 ObjectType t = parseObjectType(sig, cur, false); 1065 ifBound.add(t); 1066 } 1067 1068 TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd, 1069 classBound, ifBound.toArray(new ObjectType[ifBound.size()])); 1070 typeParam.add(p); 1071 } 1072 1073 cur.position++; 1074 } 1075 1076 return typeParam.toArray(new TypeParameter[typeParam.size()]); 1077 } 1078 parseObjectType(String sig, Cursor c, boolean dontThrow)1079 private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow) 1080 throws BadBytecode 1081 { 1082 int i; 1083 int begin = c.position; 1084 switch (sig.charAt(begin)) { 1085 case 'L' : 1086 return parseClassType2(sig, c, null); 1087 case 'T' : 1088 i = c.indexOf(sig, ';'); 1089 return new TypeVariable(sig, begin + 1, i); 1090 case '[' : 1091 return parseArray(sig, c); 1092 default : 1093 if (dontThrow) 1094 return null; 1095 throw error(sig); 1096 } 1097 } 1098 parseClassType(String sig, Cursor c)1099 private static ClassType parseClassType(String sig, Cursor c) 1100 throws BadBytecode 1101 { 1102 if (sig.charAt(c.position) == 'L') 1103 return parseClassType2(sig, c, null); 1104 throw error(sig); 1105 } 1106 parseClassType2(String sig, Cursor c, ClassType parent)1107 private static ClassType parseClassType2(String sig, Cursor c, ClassType parent) 1108 throws BadBytecode 1109 { 1110 int start = ++c.position; 1111 char t; 1112 do { 1113 t = sig.charAt(c.position++); 1114 } while (t != '$' && t != '<' && t != ';'); 1115 int end = c.position - 1; 1116 TypeArgument[] targs; 1117 if (t == '<') { 1118 targs = parseTypeArgs(sig, c); 1119 t = sig.charAt(c.position++); 1120 } 1121 else 1122 targs = null; 1123 1124 ClassType thisClass = ClassType.make(sig, start, end, targs, parent); 1125 if (t == '$' || t == '.') { 1126 c.position--; 1127 return parseClassType2(sig, c, thisClass); 1128 } 1129 return thisClass; 1130 } 1131 parseTypeArgs(String sig, Cursor c)1132 private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode { 1133 List<TypeArgument> args = new ArrayList<TypeArgument>(); 1134 char t; 1135 while ((t = sig.charAt(c.position++)) != '>') { 1136 TypeArgument ta; 1137 if (t == '*' ) 1138 ta = new TypeArgument(null, '*'); 1139 else { 1140 if (t != '+' && t != '-') { 1141 t = ' '; 1142 c.position--; 1143 } 1144 1145 ta = new TypeArgument(parseObjectType(sig, c, false), t); 1146 } 1147 1148 args.add(ta); 1149 } 1150 1151 return args.toArray(new TypeArgument[args.size()]); 1152 } 1153 parseArray(String sig, Cursor c)1154 private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode { 1155 int dim = 1; 1156 while (sig.charAt(++c.position) == '[') 1157 dim++; 1158 1159 return new ArrayType(dim, parseType(sig, c)); 1160 } 1161 parseType(String sig, Cursor c)1162 private static Type parseType(String sig, Cursor c) throws BadBytecode { 1163 Type t = parseObjectType(sig, c, true); 1164 if (t == null) 1165 t = new BaseType(sig.charAt(c.position++)); 1166 1167 return t; 1168 } 1169 error(String sig)1170 private static BadBytecode error(String sig) { 1171 return new BadBytecode("bad signature: " + sig); 1172 } 1173 } 1174