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 16 package javassist.bytecode; 17 18 import java.io.DataInputStream; 19 import java.io.IOException; 20 import java.util.Map; 21 import java.util.ArrayList; 22 import javassist.CtClass; 23 24 /** 25 * <code>Signature_attribute</code>. 26 */ 27 public class SignatureAttribute extends AttributeInfo { 28 /** 29 * The name of this attribute <code>"Signature"</code>. 30 */ 31 public static final String tag = "Signature"; 32 SignatureAttribute(ConstPool cp, int n, DataInputStream in)33 SignatureAttribute(ConstPool cp, int n, DataInputStream in) 34 throws IOException 35 { 36 super(cp, n, in); 37 } 38 39 /** 40 * Constructs a Signature attribute. 41 * 42 * @param cp a constant pool table. 43 * @param signature the signature represented by this attribute. 44 */ SignatureAttribute(ConstPool cp, String signature)45 public SignatureAttribute(ConstPool cp, String signature) { 46 super(cp, tag); 47 int index = cp.addUtf8Info(signature); 48 byte[] bvalue = new byte[2]; 49 bvalue[0] = (byte)(index >>> 8); 50 bvalue[1] = (byte)index; 51 set(bvalue); 52 } 53 54 /** 55 * Returns the signature indicated by <code>signature_index</code>. 56 * 57 * @see #toClassSignature(String) 58 * @see #toMethodSignature(String) 59 */ getSignature()60 public String getSignature() { 61 return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); 62 } 63 64 /** 65 * Sets <code>signature_index</code> to the index of the given signature, 66 * which is added to a constant pool. 67 * 68 * @param sig new signature. 69 * @since 3.11 70 */ setSignature(String sig)71 public void setSignature(String sig) { 72 int index = getConstPool().addUtf8Info(sig); 73 ByteArray.write16bit(index, info, 0); 74 } 75 76 /** 77 * Makes a copy. Class names are replaced according to the 78 * given <code>Map</code> object. 79 * 80 * @param newCp the constant pool table used by the new copy. 81 * @param classnames pairs of replaced and substituted 82 * class names. 83 */ copy(ConstPool newCp, Map classnames)84 public AttributeInfo copy(ConstPool newCp, Map classnames) { 85 return new SignatureAttribute(newCp, getSignature()); 86 } 87 renameClass(String oldname, String newname)88 void renameClass(String oldname, String newname) { 89 String sig = renameClass(getSignature(), oldname, newname); 90 setSignature(sig); 91 } 92 renameClass(Map classnames)93 void renameClass(Map classnames) { 94 String sig = renameClass(getSignature(), classnames); 95 setSignature(sig); 96 } 97 renameClass(String desc, String oldname, String newname)98 static String renameClass(String desc, String oldname, String newname) { 99 Map map = new java.util.HashMap(); 100 map.put(oldname, newname); 101 return renameClass(desc, map); 102 } 103 renameClass(String desc, Map map)104 static String renameClass(String desc, Map map) { 105 if (map == null) 106 return desc; 107 108 StringBuilder newdesc = new StringBuilder(); 109 int head = 0; 110 int i = 0; 111 for (;;) { 112 int j = desc.indexOf('L', i); 113 if (j < 0) 114 break; 115 116 StringBuilder nameBuf = new StringBuilder(); 117 int k = j; 118 char c; 119 try { 120 while ((c = desc.charAt(++k)) != ';') { 121 nameBuf.append(c); 122 if (c == '<') { 123 while ((c = desc.charAt(++k)) != '>') 124 nameBuf.append(c); 125 126 nameBuf.append(c); 127 } 128 } 129 } 130 catch (IndexOutOfBoundsException e) { break; } 131 i = k + 1; 132 String name = nameBuf.toString(); 133 String name2 = (String)map.get(name); 134 if (name2 != null) { 135 newdesc.append(desc.substring(head, j)); 136 newdesc.append('L'); 137 newdesc.append(name2); 138 newdesc.append(c); 139 head = i; 140 } 141 } 142 143 if (head == 0) 144 return desc; 145 else { 146 int len = desc.length(); 147 if (head < len) 148 newdesc.append(desc.substring(head, len)); 149 150 return newdesc.toString(); 151 } 152 } 153 isNamePart(int c)154 private static boolean isNamePart(int c) { 155 return c != ';' && c != '<'; 156 } 157 158 static private class Cursor { 159 int position = 0; 160 indexOf(String s, int ch)161 int indexOf(String s, int ch) throws BadBytecode { 162 int i = s.indexOf(ch, position); 163 if (i < 0) 164 throw error(s); 165 else { 166 position = i + 1; 167 return i; 168 } 169 } 170 } 171 172 /** 173 * Class signature. 174 */ 175 public static class ClassSignature { 176 TypeParameter[] params; 177 ClassType superClass; 178 ClassType[] interfaces; ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i)179 ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i) { 180 params = p; 181 superClass = s; 182 interfaces = i; 183 } 184 185 /** 186 * Returns the type parameters. 187 * 188 * @return a zero-length array if the type parameters are not specified. 189 */ getParameters()190 public TypeParameter[] getParameters() { 191 return params; 192 } 193 194 /** 195 * Returns the super class. 196 */ getSuperClass()197 public ClassType getSuperClass() { return superClass; } 198 199 /** 200 * Returns the super interfaces. 201 * 202 * @return a zero-length array if the super interfaces are not specified. 203 */ getInterfaces()204 public ClassType[] getInterfaces() { return interfaces; } 205 206 /** 207 * Returns the string representation. 208 */ toString()209 public String toString() { 210 StringBuffer sbuf = new StringBuffer(); 211 212 TypeParameter.toString(sbuf, params); 213 sbuf.append(" extends ").append(superClass); 214 if (interfaces.length > 0) { 215 sbuf.append(" implements "); 216 Type.toString(sbuf, interfaces); 217 } 218 219 return sbuf.toString(); 220 } 221 } 222 223 /** 224 * Method type signature. 225 */ 226 public static class MethodSignature { 227 TypeParameter[] typeParams; 228 Type[] params; 229 Type retType; 230 ObjectType[] exceptions; 231 MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex)232 MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex) { 233 typeParams = tp; 234 params = p; 235 retType = ret; 236 exceptions = ex; 237 } 238 239 /** 240 * Returns the formal type parameters. 241 * 242 * @return a zero-length array if the type parameters are not specified. 243 */ getTypeParameters()244 public TypeParameter[] getTypeParameters() { return typeParams; } 245 246 /** 247 * Returns the types of the formal parameters. 248 * 249 * @return a zero-length array if no formal parameter is taken. 250 */ getParameterTypes()251 public Type[] getParameterTypes() { return params; } 252 253 /** 254 * Returns the type of the returned value. 255 */ getReturnType()256 public Type getReturnType() { return retType; } 257 258 /** 259 * Returns the types of the exceptions that may be thrown. 260 * 261 * @return a zero-length array if exceptions are never thrown or 262 * the exception types are not parameterized types or type variables. 263 */ getExceptionTypes()264 public ObjectType[] getExceptionTypes() { return exceptions; } 265 266 /** 267 * Returns the string representation. 268 */ toString()269 public String toString() { 270 StringBuffer sbuf = new StringBuffer(); 271 272 TypeParameter.toString(sbuf, typeParams); 273 sbuf.append(" ("); 274 Type.toString(sbuf, params); 275 sbuf.append(") "); 276 sbuf.append(retType); 277 if (exceptions.length > 0) { 278 sbuf.append(" throws "); 279 Type.toString(sbuf, exceptions); 280 } 281 282 return sbuf.toString(); 283 } 284 } 285 286 /** 287 * Formal type parameters. 288 */ 289 public static class TypeParameter { 290 String name; 291 ObjectType superClass; 292 ObjectType[] superInterfaces; 293 TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si)294 TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) { 295 name = sig.substring(nb, ne); 296 superClass = sc; 297 superInterfaces = si; 298 } 299 300 /** 301 * Returns the name of the type parameter. 302 */ getName()303 public String getName() { 304 return name; 305 } 306 307 /** 308 * Returns the class bound of this parameter. 309 * 310 * @return null if the class bound is not specified. 311 */ getClassBound()312 public ObjectType getClassBound() { return superClass; } 313 314 /** 315 * Returns the interface bound of this parameter. 316 * 317 * @return a zero-length array if the interface bound is not specified. 318 */ getInterfaceBound()319 public ObjectType[] getInterfaceBound() { return superInterfaces; } 320 321 /** 322 * Returns the string representation. 323 */ toString()324 public String toString() { 325 StringBuffer sbuf = new StringBuffer(getName()); 326 if (superClass != null) 327 sbuf.append(" extends ").append(superClass.toString()); 328 329 int len = superInterfaces.length; 330 if (len > 0) { 331 for (int i = 0; i < len; i++) { 332 if (i > 0 || superClass != null) 333 sbuf.append(" & "); 334 else 335 sbuf.append(" extends "); 336 337 sbuf.append(superInterfaces[i].toString()); 338 } 339 } 340 341 return sbuf.toString(); 342 } 343 toString(StringBuffer sbuf, TypeParameter[] tp)344 static void toString(StringBuffer sbuf, TypeParameter[] tp) { 345 sbuf.append('<'); 346 for (int i = 0; i < tp.length; i++) { 347 if (i > 0) 348 sbuf.append(", "); 349 350 sbuf.append(tp[i]); 351 } 352 353 sbuf.append('>'); 354 } 355 } 356 357 /** 358 * Type argument. 359 */ 360 public static class TypeArgument { 361 ObjectType arg; 362 char wildcard; 363 TypeArgument(ObjectType a, char w)364 TypeArgument(ObjectType a, char w) { 365 arg = a; 366 wildcard = w; 367 } 368 369 /** 370 * Returns the kind of this type argument. 371 * 372 * @return <code>' '</code> (not-wildcard), <code>'*'</code> (wildcard), <code>'+'</code> (wildcard with 373 * upper bound), or <code>'-'</code> (wildcard with lower bound). 374 */ getKind()375 public char getKind() { return wildcard; } 376 377 /** 378 * Returns true if this type argument is a wildcard type 379 * such as <code>?</code>, <code>? extends String</code>, or <code>? super Integer</code>. 380 */ isWildcard()381 public boolean isWildcard() { return wildcard != ' '; } 382 383 /** 384 * Returns the type represented by this argument 385 * if the argument is not a wildcard type. Otherwise, this method 386 * returns the upper bound (if the kind is '+'), 387 * the lower bound (if the kind is '-'), or null (if the upper or lower 388 * bound is not specified). 389 */ getType()390 public ObjectType getType() { return arg; } 391 392 /** 393 * Returns the string representation. 394 */ toString()395 public String toString() { 396 if (wildcard == '*') 397 return "?"; 398 399 String type = arg.toString(); 400 if (wildcard == ' ') 401 return type; 402 else if (wildcard == '+') 403 return "? extends " + type; 404 else 405 return "? super " + type; 406 } 407 } 408 409 /** 410 * Primitive types and object types. 411 */ 412 public static abstract class Type { toString(StringBuffer sbuf, Type[] ts)413 static void toString(StringBuffer sbuf, Type[] ts) { 414 for (int i = 0; i < ts.length; i++) { 415 if (i > 0) 416 sbuf.append(", "); 417 418 sbuf.append(ts[i]); 419 } 420 } 421 } 422 423 /** 424 * Primitive types. 425 */ 426 public static class BaseType extends Type { 427 char descriptor; BaseType(char c)428 BaseType(char c) { descriptor = c; } 429 430 /** 431 * Returns the descriptor representing this primitive type. 432 * 433 * @see javassist.bytecode.Descriptor 434 */ getDescriptor()435 public char getDescriptor() { return descriptor; } 436 437 /** 438 * Returns the <code>CtClass</code> representing this 439 * primitive type. 440 */ getCtlass()441 public CtClass getCtlass() { 442 return Descriptor.toPrimitiveClass(descriptor); 443 } 444 445 /** 446 * Returns the string representation. 447 */ toString()448 public String toString() { 449 return Descriptor.toClassName(Character.toString(descriptor)); 450 } 451 } 452 453 /** 454 * Class types, array types, and type variables. 455 */ 456 public static abstract class ObjectType extends Type {} 457 458 /** 459 * Class types. 460 */ 461 public static class ClassType extends ObjectType { 462 String name; 463 TypeArgument[] arguments; 464 make(String s, int b, int e, TypeArgument[] targs, ClassType parent)465 static ClassType make(String s, int b, int e, 466 TypeArgument[] targs, ClassType parent) { 467 if (parent == null) 468 return new ClassType(s, b, e, targs); 469 else 470 return new NestedClassType(s, b, e, targs, parent); 471 } 472 ClassType(String signature, int begin, int end, TypeArgument[] targs)473 ClassType(String signature, int begin, int end, TypeArgument[] targs) { 474 name = signature.substring(begin, end).replace('/', '.'); 475 arguments = targs; 476 } 477 478 /** 479 * Returns the class name. 480 */ getName()481 public String getName() { 482 return name; 483 } 484 485 /** 486 * Returns the type arguments. 487 * 488 * @return null if no type arguments are given to this class. 489 */ getTypeArguments()490 public TypeArgument[] getTypeArguments() { return arguments; } 491 492 /** 493 * If this class is a member of another class, returns the 494 * class in which this class is declared. 495 * 496 * @return null if this class is not a member of another class. 497 */ getDeclaringClass()498 public ClassType getDeclaringClass() { return null; } 499 500 /** 501 * Returns the string representation. 502 */ toString()503 public String toString() { 504 StringBuffer sbuf = new StringBuffer(); 505 ClassType parent = getDeclaringClass(); 506 if (parent != null) 507 sbuf.append(parent.toString()).append('.'); 508 509 sbuf.append(name); 510 if (arguments != null) { 511 sbuf.append('<'); 512 int n = arguments.length; 513 for (int i = 0; i < n; i++) { 514 if (i > 0) 515 sbuf.append(", "); 516 517 sbuf.append(arguments[i].toString()); 518 } 519 520 sbuf.append('>'); 521 } 522 523 return sbuf.toString(); 524 } 525 } 526 527 /** 528 * Nested class types. 529 */ 530 public static class NestedClassType extends ClassType { 531 ClassType parent; NestedClassType(String s, int b, int e, TypeArgument[] targs, ClassType p)532 NestedClassType(String s, int b, int e, 533 TypeArgument[] targs, ClassType p) { 534 super(s, b, e, targs); 535 parent = p; 536 } 537 538 /** 539 * Returns the class that declares this nested class. 540 * This nested class is a member of that declaring class. 541 */ getDeclaringClass()542 public ClassType getDeclaringClass() { return parent; } 543 } 544 545 /** 546 * Array types. 547 */ 548 public static class ArrayType extends ObjectType { 549 int dim; 550 Type componentType; 551 ArrayType(int d, Type comp)552 public ArrayType(int d, Type comp) { 553 dim = d; 554 componentType = comp; 555 } 556 557 /** 558 * Returns the dimension of the array. 559 */ getDimension()560 public int getDimension() { return dim; } 561 562 /** 563 * Returns the component type. 564 */ getComponentType()565 public Type getComponentType() { 566 return componentType; 567 } 568 569 /** 570 * Returns the string representation. 571 */ toString()572 public String toString() { 573 StringBuffer sbuf = new StringBuffer(componentType.toString()); 574 for (int i = 0; i < dim; i++) 575 sbuf.append("[]"); 576 577 return sbuf.toString(); 578 } 579 } 580 581 /** 582 * Type variables. 583 */ 584 public static class TypeVariable extends ObjectType { 585 String name; 586 TypeVariable(String sig, int begin, int end)587 TypeVariable(String sig, int begin, int end) { 588 name = sig.substring(begin, end); 589 } 590 591 /** 592 * Returns the variable name. 593 */ getName()594 public String getName() { 595 return name; 596 } 597 598 /** 599 * Returns the string representation. 600 */ toString()601 public String toString() { 602 return name; 603 } 604 } 605 606 /** 607 * Parses the given signature string as a class signature. 608 * 609 * @param sig the signature. 610 * @throws BadBytecode thrown when a syntactical error is found. 611 * @since 3.5 612 */ toClassSignature(String sig)613 public static ClassSignature toClassSignature(String sig) throws BadBytecode { 614 try { 615 return parseSig(sig); 616 } 617 catch (IndexOutOfBoundsException e) { 618 throw error(sig); 619 } 620 } 621 622 /** 623 * Parses the given signature string as a method type signature. 624 * 625 * @param sig the signature. 626 * @throws BadBytecode thrown when a syntactical error is found. 627 * @since 3.5 628 */ toMethodSignature(String sig)629 public static MethodSignature toMethodSignature(String sig) throws BadBytecode { 630 try { 631 return parseMethodSig(sig); 632 } 633 catch (IndexOutOfBoundsException e) { 634 throw error(sig); 635 } 636 } 637 638 /** 639 * Parses the given signature string as a field type signature. 640 * 641 * @param sig the signature string. 642 * @return the field type signature. 643 * @throws BadBytecode thrown when a syntactical error is found. 644 * @since 3.5 645 */ toFieldSignature(String sig)646 public static ObjectType toFieldSignature(String sig) throws BadBytecode { 647 try { 648 return parseObjectType(sig, new Cursor(), false); 649 } 650 catch (IndexOutOfBoundsException e) { 651 throw error(sig); 652 } 653 } 654 parseSig(String sig)655 private static ClassSignature parseSig(String sig) 656 throws BadBytecode, IndexOutOfBoundsException 657 { 658 Cursor cur = new Cursor(); 659 TypeParameter[] tp = parseTypeParams(sig, cur); 660 ClassType superClass = parseClassType(sig, cur); 661 int sigLen = sig.length(); 662 ArrayList ifArray = new ArrayList(); 663 while (cur.position < sigLen && sig.charAt(cur.position) == 'L') 664 ifArray.add(parseClassType(sig, cur)); 665 666 ClassType[] ifs 667 = (ClassType[])ifArray.toArray(new ClassType[ifArray.size()]); 668 return new ClassSignature(tp, superClass, ifs); 669 } 670 parseMethodSig(String sig)671 private static MethodSignature parseMethodSig(String sig) 672 throws BadBytecode 673 { 674 Cursor cur = new Cursor(); 675 TypeParameter[] tp = parseTypeParams(sig, cur); 676 if (sig.charAt(cur.position++) != '(') 677 throw error(sig); 678 679 ArrayList params = new ArrayList(); 680 while (sig.charAt(cur.position) != ')') { 681 Type t = parseType(sig, cur); 682 params.add(t); 683 } 684 685 cur.position++; 686 Type ret = parseType(sig, cur); 687 int sigLen = sig.length(); 688 ArrayList exceptions = new ArrayList(); 689 while (cur.position < sigLen && sig.charAt(cur.position) == '^') { 690 cur.position++; 691 ObjectType t = parseObjectType(sig, cur, false); 692 if (t instanceof ArrayType) 693 throw error(sig); 694 695 exceptions.add(t); 696 } 697 698 Type[] p = (Type[])params.toArray(new Type[params.size()]); 699 ObjectType[] ex = (ObjectType[])exceptions.toArray(new ObjectType[exceptions.size()]); 700 return new MethodSignature(tp, p, ret, ex); 701 } 702 parseTypeParams(String sig, Cursor cur)703 private static TypeParameter[] parseTypeParams(String sig, Cursor cur) 704 throws BadBytecode 705 { 706 ArrayList typeParam = new ArrayList(); 707 if (sig.charAt(cur.position) == '<') { 708 cur.position++; 709 while (sig.charAt(cur.position) != '>') { 710 int nameBegin = cur.position; 711 int nameEnd = cur.indexOf(sig, ':'); 712 ObjectType classBound = parseObjectType(sig, cur, true); 713 ArrayList ifBound = new ArrayList(); 714 while (sig.charAt(cur.position) == ':') { 715 cur.position++; 716 ObjectType t = parseObjectType(sig, cur, false); 717 ifBound.add(t); 718 } 719 720 TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd, 721 classBound, (ObjectType[])ifBound.toArray(new ObjectType[ifBound.size()])); 722 typeParam.add(p); 723 } 724 725 cur.position++; 726 } 727 728 return (TypeParameter[])typeParam.toArray(new TypeParameter[typeParam.size()]); 729 } 730 parseObjectType(String sig, Cursor c, boolean dontThrow)731 private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow) 732 throws BadBytecode 733 { 734 int i; 735 int begin = c.position; 736 switch (sig.charAt(begin)) { 737 case 'L' : 738 return parseClassType2(sig, c, null); 739 case 'T' : 740 i = c.indexOf(sig, ';'); 741 return new TypeVariable(sig, begin + 1, i); 742 case '[' : 743 return parseArray(sig, c); 744 default : 745 if (dontThrow) 746 return null; 747 else 748 throw error(sig); 749 } 750 } 751 parseClassType(String sig, Cursor c)752 private static ClassType parseClassType(String sig, Cursor c) 753 throws BadBytecode 754 { 755 if (sig.charAt(c.position) == 'L') 756 return parseClassType2(sig, c, null); 757 else 758 throw error(sig); 759 } 760 parseClassType2(String sig, Cursor c, ClassType parent)761 private static ClassType parseClassType2(String sig, Cursor c, ClassType parent) 762 throws BadBytecode 763 { 764 int start = ++c.position; 765 char t; 766 do { 767 t = sig.charAt(c.position++); 768 } while (t != '$' && t != '<' && t != ';'); 769 int end = c.position - 1; 770 TypeArgument[] targs; 771 if (t == '<') { 772 targs = parseTypeArgs(sig, c); 773 t = sig.charAt(c.position++); 774 } 775 else 776 targs = null; 777 778 ClassType thisClass = ClassType.make(sig, start, end, targs, parent); 779 if (t == '$') { 780 c.position--; 781 return parseClassType2(sig, c, thisClass); 782 } 783 else 784 return thisClass; 785 } 786 parseTypeArgs(String sig, Cursor c)787 private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode { 788 ArrayList args = new ArrayList(); 789 char t; 790 while ((t = sig.charAt(c.position++)) != '>') { 791 TypeArgument ta; 792 if (t == '*' ) 793 ta = new TypeArgument(null, '*'); 794 else { 795 if (t != '+' && t != '-') { 796 t = ' '; 797 c.position--; 798 } 799 800 ta = new TypeArgument(parseObjectType(sig, c, false), t); 801 } 802 803 args.add(ta); 804 } 805 806 return (TypeArgument[])args.toArray(new TypeArgument[args.size()]); 807 } 808 parseArray(String sig, Cursor c)809 private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode { 810 int dim = 1; 811 while (sig.charAt(++c.position) == '[') 812 dim++; 813 814 return new ArrayType(dim, parseType(sig, c)); 815 } 816 parseType(String sig, Cursor c)817 private static Type parseType(String sig, Cursor c) throws BadBytecode { 818 Type t = parseObjectType(sig, c, true); 819 if (t == null) 820 t = new BaseType(sig.charAt(c.position++)); 821 822 return t; 823 } 824 error(String sig)825 private static BadBytecode error(String sig) { 826 return new BadBytecode("bad signature: " + sig); 827 } 828 } 829