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