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.File; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.OutputStream; 24 import java.net.URL; 25 import java.security.ProtectionDomain; 26 import java.util.ArrayList; 27 import java.util.Enumeration; 28 import java.util.Hashtable; 29 import java.util.Iterator; 30 31 import javassist.bytecode.ClassFile; 32 import javassist.bytecode.Descriptor; 33 import javassist.util.proxy.DefinePackageHelper; 34 35 /** 36 * A container of <code>CtClass</code> objects. 37 * A <code>CtClass</code> object must be obtained from this object. 38 * If <code>get()</code> is called on this object, 39 * it searches various sources represented by <code>ClassPath</code> 40 * to find a class file and then it creates a <code>CtClass</code> object 41 * representing that class file. The created object is returned to the 42 * caller. 43 * 44 * <p><b>Memory consumption memo:</b> 45 * 46 * <p><code>ClassPool</code> objects hold all the <code>CtClass</code>es 47 * that have been created so that the consistency among modified classes 48 * can be guaranteed. Thus if a large number of <code>CtClass</code>es 49 * are processed, the <code>ClassPool</code> will consume a huge amount 50 * of memory. To avoid this, a <code>ClassPool</code> object 51 * should be recreated, for example, every hundred classes processed. 52 * Note that <code>getDefault()</code> is a singleton factory. 53 * Otherwise, <code>detach()</code> in <code>CtClass</code> should be used 54 * to avoid huge memory consumption. 55 * 56 * <p><b><code>ClassPool</code> hierarchy:</b> 57 * 58 * <p><code>ClassPool</code>s can make a parent-child hierarchy as 59 * <code>java.lang.ClassLoader</code>s. If a <code>ClassPool</code> has 60 * a parent pool, <code>get()</code> first asks the parent pool to find 61 * a class file. Only if the parent could not find the class file, 62 * <code>get()</code> searches the <code>ClassPath</code>s of 63 * the child <code>ClassPool</code>. This search order is reversed if 64 * <code>ClassPath.childFirstLookup</code> is <code>true</code>. 65 * 66 * @see javassist.CtClass 67 * @see javassist.ClassPath 68 */ 69 @SuppressWarnings({"unchecked", "rawtypes"}) 70 public class ClassPool { 71 72 /** 73 * Determines the search order. 74 * 75 * <p>If this field is true, <code>get()</code> first searches the 76 * class path associated to this <code>ClassPool</code> and then 77 * the class path associated with the parent <code>ClassPool</code>. 78 * Otherwise, the class path associated with the parent is searched 79 * first. 80 * 81 * <p>The default value is false. 82 */ 83 public boolean childFirstLookup = false; 84 85 /** 86 * Turning the automatic pruning on/off. 87 * 88 * <p>If this field is true, <code>CtClass</code> objects are 89 * automatically pruned by default when <code>toBytecode()</code> etc. 90 * are called. The automatic pruning can be turned on/off individually 91 * for each <code>CtClass</code> object. 92 * 93 * <p>The initial value is false. 94 * 95 * @see CtClass#prune() 96 * @see CtClass#stopPruning(boolean) 97 * @see CtClass#detach() 98 */ 99 public static boolean doPruning = false; 100 101 private int compressCount; 102 private static final int COMPRESS_THRESHOLD = 100; 103 104 /* releaseUnmodifiedClassFile was introduced for avoiding a bug 105 of JBoss AOP. So the value should be true except for JBoss AOP. 106 */ 107 108 /** 109 * If true, unmodified and not-recently-used class files are 110 * periodically released for saving memory. 111 * 112 * <p>The initial value is true. 113 */ 114 public static boolean releaseUnmodifiedClassFile = true; 115 116 protected ClassPoolTail source; 117 protected ClassPool parent; 118 protected Hashtable classes; // should be synchronous 119 120 /** 121 * Table of registered cflow variables. 122 */ 123 private Hashtable cflow = null; // should be synchronous. 124 125 private static final int INIT_HASH_SIZE = 191; 126 127 private ArrayList importedPackages; 128 129 /** 130 * Creates a root class pool. No parent class pool is specified. 131 */ ClassPool()132 public ClassPool() { 133 this(null); 134 } 135 136 /** 137 * Creates a root class pool. If <code>useDefaultPath</code> is 138 * true, <code>appendSystemPath()</code> is called. Otherwise, 139 * this constructor is equivalent to the constructor taking no 140 * parameter. 141 * 142 * @param useDefaultPath true if the system search path is 143 * appended. 144 */ ClassPool(boolean useDefaultPath)145 public ClassPool(boolean useDefaultPath) { 146 this(null); 147 if (useDefaultPath) 148 appendSystemPath(); 149 } 150 151 /** 152 * Creates a class pool. 153 * 154 * @param parent the parent of this class pool. If this is a root 155 * class pool, this parameter must be <code>null</code>. 156 * @see javassist.ClassPool#getDefault() 157 */ ClassPool(ClassPool parent)158 public ClassPool(ClassPool parent) { 159 this.classes = new Hashtable(INIT_HASH_SIZE); 160 this.source = new ClassPoolTail(); 161 this.parent = parent; 162 if (parent == null) { 163 CtClass[] pt = CtClass.primitiveTypes; 164 for (int i = 0; i < pt.length; ++i) 165 classes.put(pt[i].getName(), pt[i]); 166 } 167 168 this.cflow = null; 169 this.compressCount = 0; 170 clearImportedPackages(); 171 } 172 173 /** 174 * Returns the default class pool. 175 * The returned object is always identical since this method is 176 * a singleton factory. 177 * 178 * <p>The default class pool searches the system search path, 179 * which usually includes the platform library, extension 180 * libraries, and the search path specified by the 181 * <code>-classpath</code> option or the <code>CLASSPATH</code> 182 * environment variable. 183 * 184 * <p>When this method is called for the first time, the default 185 * class pool is created with the following code snippet: 186 * 187 * <pre>ClassPool cp = new ClassPool(); 188 * cp.appendSystemPath(); 189 * </pre> 190 * 191 * <p>If the default class pool cannot find any class files, 192 * try <code>ClassClassPath</code>, <code>ModuleClassPath</code>, 193 * or <code>LoaderClassPath</code>. 194 * 195 * @see ClassClassPath 196 * @see LoaderClassPath 197 */ getDefault()198 public static synchronized ClassPool getDefault() { 199 if (defaultPool == null) { 200 defaultPool = new ClassPool(null); 201 defaultPool.appendSystemPath(); 202 } 203 204 return defaultPool; 205 } 206 207 private static ClassPool defaultPool = null; 208 209 /** 210 * Provide a hook so that subclasses can do their own 211 * caching of classes. 212 * 213 * @see #cacheCtClass(String,CtClass,boolean) 214 * @see #removeCached(String) 215 */ getCached(String classname)216 protected CtClass getCached(String classname) { 217 return (CtClass)classes.get(classname); 218 } 219 220 /** 221 * Provides a hook so that subclasses can do their own 222 * caching of classes. 223 * 224 * @see #getCached(String) 225 * @see #removeCached(String) 226 */ cacheCtClass(String classname, CtClass c, boolean dynamic)227 protected void cacheCtClass(String classname, CtClass c, boolean dynamic) { 228 classes.put(classname, c); 229 } 230 231 /** 232 * Provide a hook so that subclasses can do their own 233 * caching of classes. 234 * 235 * @see #getCached(String) 236 * @see #cacheCtClass(String,CtClass,boolean) 237 */ removeCached(String classname)238 protected CtClass removeCached(String classname) { 239 return (CtClass)classes.remove(classname); 240 } 241 242 /** 243 * Returns the class search path. 244 */ toString()245 public String toString() { 246 return source.toString(); 247 } 248 249 /** 250 * This method is periodically invoked so that memory 251 * footprint will be minimized. 252 */ compress()253 void compress() { 254 if (compressCount++ > COMPRESS_THRESHOLD) { 255 compressCount = 0; 256 Enumeration e = classes.elements(); 257 while (e.hasMoreElements()) 258 ((CtClass)e.nextElement()).compress(); 259 } 260 } 261 262 /** 263 * Record a package name so that the Javassist compiler searches 264 * the package to resolve a class name. 265 * Don't record the <code>java.lang</code> package, which has 266 * been implicitly recorded by default. 267 * 268 * <p>Since version 3.14, <code>packageName</code> can be a 269 * fully-qualified class name. 270 * 271 * <p>Note that <code>get()</code> in <code>ClassPool</code> does 272 * not search the recorded package. Only the compiler searches it. 273 * 274 * @param packageName the package name. 275 * It must not include the last '.' (dot). 276 * For example, "java.util" is valid but "java.util." is wrong. 277 * @since 3.1 278 */ importPackage(String packageName)279 public void importPackage(String packageName) { 280 importedPackages.add(packageName); 281 } 282 283 /** 284 * Clear all the package names recorded by <code>importPackage()</code>. 285 * The <code>java.lang</code> package is not removed. 286 * 287 * @see #importPackage(String) 288 * @since 3.1 289 */ clearImportedPackages()290 public void clearImportedPackages() { 291 importedPackages = new ArrayList(); 292 importedPackages.add("java.lang"); 293 } 294 295 /** 296 * Returns all the package names recorded by <code>importPackage()</code>. 297 * 298 * @see #importPackage(String) 299 * @since 3.1 300 */ getImportedPackages()301 public Iterator<String> getImportedPackages() { 302 return importedPackages.iterator(); 303 } 304 305 /** 306 * Records a class name that never exists. 307 * For example, a package name can be recorded by this method. 308 * This would improve execution performance 309 * since <code>get()</code> quickly throw an exception 310 * without searching the class path at all 311 * if the given name is an invalid name recorded by this method. 312 * Note that searching the class path takes relatively long time. 313 * 314 * <p>The current implementation of this method performs nothing. 315 * 316 * @param name an invalid class name (separeted by dots). 317 * @deprecated 318 */ recordInvalidClassName(String name)319 public void recordInvalidClassName(String name) { 320 // source.recordInvalidClassName(name); 321 } 322 323 /** 324 * Records the <code>$cflow</code> variable for the field specified 325 * by <code>cname</code> and <code>fname</code>. 326 * 327 * @param name variable name 328 * @param cname class name 329 * @param fname field name 330 */ recordCflow(String name, String cname, String fname)331 void recordCflow(String name, String cname, String fname) { 332 if (cflow == null) 333 cflow = new Hashtable(); 334 335 cflow.put(name, new Object[] { cname, fname }); 336 } 337 338 /** 339 * Undocumented method. Do not use; internal-use only. 340 * 341 * @param name the name of <code>$cflow</code> variable 342 */ lookupCflow(String name)343 public Object[] lookupCflow(String name) { 344 if (cflow == null) 345 cflow = new Hashtable(); 346 347 return (Object[])cflow.get(name); 348 } 349 350 /** 351 * Reads a class file and constructs a <code>CtClass</code> 352 * object with a new name. 353 * This method is useful if you want to generate a new class as a copy 354 * of another class (except the class name). For example, 355 * 356 * <pre> 357 * getAndRename("Point", "Pair") 358 * </pre> 359 * 360 * returns a <code>CtClass</code> object representing <code>Pair</code> 361 * class. The definition of <code>Pair</code> is the same as that of 362 * <code>Point</code> class except the class name since <code>Pair</code> 363 * is defined by reading <code>Point.class</code>. 364 * 365 * @param orgName the original (fully-qualified) class name 366 * @param newName the new class name 367 */ getAndRename(String orgName, String newName)368 public CtClass getAndRename(String orgName, String newName) 369 throws NotFoundException 370 { 371 CtClass clazz = get0(orgName, false); 372 if (clazz == null) 373 throw new NotFoundException(orgName); 374 375 if (clazz instanceof CtClassType) 376 ((CtClassType)clazz).setClassPool(this); 377 378 clazz.setName(newName); // indirectly calls 379 // classNameChanged() in this class 380 return clazz; 381 } 382 383 /* 384 * This method is invoked by CtClassType.setName(). It removes a 385 * CtClass object from the hash table and inserts it with the new 386 * name. Don't delegate to the parent. 387 */ classNameChanged(String oldname, CtClass clazz)388 synchronized void classNameChanged(String oldname, CtClass clazz) { 389 CtClass c = (CtClass)getCached(oldname); 390 if (c == clazz) // must check this equation. 391 removeCached(oldname); // see getAndRename(). 392 393 String newName = clazz.getName(); 394 checkNotFrozen(newName); 395 cacheCtClass(newName, clazz, false); 396 } 397 398 /** 399 * Reads a class file from the source and returns a reference 400 * to the <code>CtClass</code> 401 * object representing that class file. If that class file has been 402 * already read, this method returns a reference to the 403 * <code>CtClass</code> created when that class file was read at the 404 * first time. 405 * 406 * <p>If <code>classname</code> ends with "[]", then this method 407 * returns a <code>CtClass</code> object for that array type. 408 * 409 * <p>To obtain an inner class, use "$" instead of "." for separating 410 * the enclosing class name and the inner class name. 411 * 412 * @param classname a fully-qualified class name. 413 */ get(String classname)414 public CtClass get(String classname) throws NotFoundException { 415 CtClass clazz; 416 if (classname == null) 417 clazz = null; 418 else 419 clazz = get0(classname, true); 420 421 if (clazz == null) 422 throw new NotFoundException(classname); 423 else { 424 clazz.incGetCounter(); 425 return clazz; 426 } 427 } 428 429 /** 430 * Reads a class file from the source and returns a reference 431 * to the <code>CtClass</code> 432 * object representing that class file. 433 * This method is equivalent to <code>get</code> except 434 * that it returns <code>null</code> when a class file is 435 * not found and it never throws an exception. 436 * 437 * @param classname a fully-qualified class name. 438 * @return a <code>CtClass</code> object or <code>null</code>. 439 * @see #get(String) 440 * @see #find(String) 441 * @since 3.13 442 */ getOrNull(String classname)443 public CtClass getOrNull(String classname) { 444 CtClass clazz = null; 445 if (classname == null) 446 clazz = null; 447 else 448 try { 449 /* ClassPool.get0() never throws an exception 450 but its subclass may implement get0 that 451 may throw an exception. 452 */ 453 clazz = get0(classname, true); 454 } 455 catch (NotFoundException e){} 456 457 if (clazz != null) 458 clazz.incGetCounter(); 459 460 return clazz; 461 } 462 463 /** 464 * Returns a <code>CtClass</code> object with the given name. 465 * This is almost equivalent to <code>get(String)</code> except 466 * that classname can be an array-type "descriptor" (an encoded 467 * type name) such as <code>[Ljava/lang/Object;</code>. 468 * 469 * <p>Using this method is not recommended; this method should be 470 * used only to obtain the <code>CtClass</code> object 471 * with a name returned from <code>getClassInfo</code> in 472 * <code>javassist.bytecode.ClassPool</code>. <code>getClassInfo</code> 473 * returns a fully-qualified class name but, if the class is an array 474 * type, it returns a descriptor. 475 * 476 * @param classname a fully-qualified class name or a descriptor 477 * representing an array type. 478 * @see #get(String) 479 * @see javassist.bytecode.ConstPool#getClassInfo(int) 480 * @see javassist.bytecode.Descriptor#toCtClass(String, ClassPool) 481 * @since 3.8.1 482 */ getCtClass(String classname)483 public CtClass getCtClass(String classname) throws NotFoundException { 484 if (classname.charAt(0) == '[') 485 return Descriptor.toCtClass(classname, this); 486 else 487 return get(classname); 488 } 489 490 /** 491 * @param useCache false if the cached CtClass must be ignored. 492 * @return null if the class could not be found. 493 */ get0(String classname, boolean useCache)494 protected synchronized CtClass get0(String classname, boolean useCache) 495 throws NotFoundException 496 { 497 CtClass clazz = null; 498 if (useCache) { 499 clazz = getCached(classname); 500 if (clazz != null) 501 return clazz; 502 } 503 504 if (!childFirstLookup && parent != null) { 505 clazz = parent.get0(classname, useCache); 506 if (clazz != null) 507 return clazz; 508 } 509 510 clazz = createCtClass(classname, useCache); 511 if (clazz != null) { 512 // clazz.getName() != classname if classname is "[L<name>;". 513 if (useCache) 514 cacheCtClass(clazz.getName(), clazz, false); 515 516 return clazz; 517 } 518 519 if (childFirstLookup && parent != null) 520 clazz = parent.get0(classname, useCache); 521 522 return clazz; 523 } 524 525 /** 526 * Creates a CtClass object representing the specified class. 527 * It first examines whether or not the corresponding class 528 * file exists. If yes, it creates a CtClass object. 529 * 530 * @return null if the class file could not be found. 531 */ createCtClass(String classname, boolean useCache)532 protected CtClass createCtClass(String classname, boolean useCache) { 533 // accept "[L<class name>;" as a class name. 534 if (classname.charAt(0) == '[') 535 classname = Descriptor.toClassName(classname); 536 537 if (classname.endsWith("[]")) { 538 String base = classname.substring(0, classname.indexOf('[')); 539 if ((!useCache || getCached(base) == null) && find(base) == null) 540 return null; 541 else 542 return new CtArray(classname, this); 543 } 544 else 545 if (find(classname) == null) 546 return null; 547 else 548 return new CtClassType(classname, this); 549 } 550 551 /** 552 * Searches the class path to obtain the URL of the class file 553 * specified by classname. It is also used to determine whether 554 * the class file exists. 555 * 556 * @param classname a fully-qualified class name. 557 * @return null if the class file could not be found. 558 * @see CtClass#getURL() 559 */ find(String classname)560 public URL find(String classname) { 561 return source.find(classname); 562 } 563 564 /* 565 * Is invoked by CtClassType.setName() and methods in this class. 566 * This method throws an exception if the class is already frozen or 567 * if this class pool cannot edit the class since it is in a parent 568 * class pool. 569 * 570 * @see checkNotExists(String) 571 */ checkNotFrozen(String classname)572 void checkNotFrozen(String classname) throws RuntimeException { 573 CtClass clazz = getCached(classname); 574 if (clazz == null) { 575 if (!childFirstLookup && parent != null) { 576 try { 577 clazz = parent.get0(classname, true); 578 } 579 catch (NotFoundException e) {} 580 if (clazz != null) 581 throw new RuntimeException(classname 582 + " is in a parent ClassPool. Use the parent."); 583 } 584 } 585 else 586 if (clazz.isFrozen()) 587 throw new RuntimeException(classname 588 + ": frozen class (cannot edit)"); 589 } 590 591 /* 592 * This method returns null if this or its parent class pool does 593 * not contain a CtClass object with the class name. 594 * 595 * @see checkNotFrozen(String) 596 */ checkNotExists(String classname)597 CtClass checkNotExists(String classname) { 598 CtClass clazz = getCached(classname); 599 if (clazz == null) 600 if (!childFirstLookup && parent != null) { 601 try { 602 clazz = parent.get0(classname, true); 603 } 604 catch (NotFoundException e) {} 605 } 606 607 return clazz; 608 } 609 610 /* for CtClassType.getClassFile2(). Don't delegate to the parent. 611 */ openClassfile(String classname)612 InputStream openClassfile(String classname) throws NotFoundException { 613 return source.openClassfile(classname); 614 } 615 writeClassfile(String classname, OutputStream out)616 void writeClassfile(String classname, OutputStream out) 617 throws NotFoundException, IOException, CannotCompileException 618 { 619 source.writeClassfile(classname, out); 620 } 621 622 /** 623 * Reads class files from the source and returns an array of 624 * <code>CtClass</code> 625 * objects representing those class files. 626 * 627 * <p>If an element of <code>classnames</code> ends with "[]", 628 * then this method 629 * returns a <code>CtClass</code> object for that array type. 630 * 631 * @param classnames an array of fully-qualified class name. 632 */ get(String[] classnames)633 public CtClass[] get(String[] classnames) throws NotFoundException { 634 if (classnames == null) 635 return new CtClass[0]; 636 637 int num = classnames.length; 638 CtClass[] result = new CtClass[num]; 639 for (int i = 0; i < num; ++i) 640 result[i] = get(classnames[i]); 641 642 return result; 643 } 644 645 /** 646 * Reads a class file and obtains a compile-time method. 647 * 648 * @param classname the class name 649 * @param methodname the method name 650 * @see CtClass#getDeclaredMethod(String) 651 */ getMethod(String classname, String methodname)652 public CtMethod getMethod(String classname, String methodname) 653 throws NotFoundException 654 { 655 CtClass c = get(classname); 656 return c.getDeclaredMethod(methodname); 657 } 658 659 /** 660 * Creates a new class (or interface) from the given class file. 661 * If there already exists a class with the same name, the new class 662 * overwrites that previous class. 663 * 664 * <p>This method is used for creating a <code>CtClass</code> object 665 * directly from a class file. The qualified class name is obtained 666 * from the class file; you do not have to explicitly give the name. 667 * 668 * @param classfile class file. 669 * @throws RuntimeException if there is a frozen class with the 670 * the same name. 671 * @see #makeClassIfNew(InputStream) 672 * @see javassist.ByteArrayClassPath 673 */ makeClass(InputStream classfile)674 public CtClass makeClass(InputStream classfile) 675 throws IOException, RuntimeException 676 { 677 return makeClass(classfile, true); 678 } 679 680 /** 681 * Creates a new class (or interface) from the given class file. 682 * If there already exists a class with the same name, the new class 683 * overwrites that previous class. 684 * 685 * <p>This method is used for creating a <code>CtClass</code> object 686 * directly from a class file. The qualified class name is obtained 687 * from the class file; you do not have to explicitly give the name. 688 * 689 * @param classfile class file. 690 * @param ifNotFrozen throws a RuntimeException if this parameter is true 691 * and there is a frozen class with the same name. 692 * @see javassist.ByteArrayClassPath 693 */ makeClass(InputStream classfile, boolean ifNotFrozen)694 public CtClass makeClass(InputStream classfile, boolean ifNotFrozen) 695 throws IOException, RuntimeException 696 { 697 compress(); 698 classfile = new BufferedInputStream(classfile); 699 CtClass clazz = new CtClassType(classfile, this); 700 clazz.checkModify(); 701 String classname = clazz.getName(); 702 if (ifNotFrozen) 703 checkNotFrozen(classname); 704 705 cacheCtClass(classname, clazz, true); 706 return clazz; 707 } 708 709 /** 710 * Creates a new class (or interface) from the given class file. 711 * If there already exists a class with the same name, the new class 712 * overwrites that previous class. 713 * 714 * <p>This method is used for creating a <code>CtClass</code> object 715 * directly from a class file. The qualified class name is obtained 716 * from the class file; you do not have to explicitly give the name. 717 * 718 * @param classfile class file. 719 * @throws RuntimeException if there is a frozen class with the 720 * the same name. 721 * @since 3.20 722 */ makeClass(ClassFile classfile)723 public CtClass makeClass(ClassFile classfile) 724 throws RuntimeException 725 { 726 return makeClass(classfile, true); 727 } 728 729 /** 730 * Creates a new class (or interface) from the given class file. 731 * If there already exists a class with the same name, the new class 732 * overwrites that previous class. 733 * 734 * <p>This method is used for creating a <code>CtClass</code> object 735 * directly from a class file. The qualified class name is obtained 736 * from the class file; you do not have to explicitly give the name. 737 * 738 * @param classfile class file. 739 * @param ifNotFrozen throws a RuntimeException if this parameter is true 740 * and there is a frozen class with the same name. 741 * @since 3.20 742 */ makeClass(ClassFile classfile, boolean ifNotFrozen)743 public CtClass makeClass(ClassFile classfile, boolean ifNotFrozen) 744 throws RuntimeException 745 { 746 compress(); 747 CtClass clazz = new CtClassType(classfile, this); 748 clazz.checkModify(); 749 String classname = clazz.getName(); 750 if (ifNotFrozen) 751 checkNotFrozen(classname); 752 753 cacheCtClass(classname, clazz, true); 754 return clazz; 755 } 756 757 /** 758 * Creates a new class (or interface) from the given class file. 759 * If there already exists a class with the same name, this method 760 * returns the existing class; a new class is never created from 761 * the given class file. 762 * 763 * <p>This method is used for creating a <code>CtClass</code> object 764 * directly from a class file. The qualified class name is obtained 765 * from the class file; you do not have to explicitly give the name. 766 * 767 * @param classfile the class file. 768 * @see #makeClass(InputStream) 769 * @see javassist.ByteArrayClassPath 770 * @since 3.9 771 */ makeClassIfNew(InputStream classfile)772 public CtClass makeClassIfNew(InputStream classfile) 773 throws IOException, RuntimeException 774 { 775 compress(); 776 classfile = new BufferedInputStream(classfile); 777 CtClass clazz = new CtClassType(classfile, this); 778 clazz.checkModify(); 779 String classname = clazz.getName(); 780 CtClass found = checkNotExists(classname); 781 if (found != null) 782 return found; 783 else { 784 cacheCtClass(classname, clazz, true); 785 return clazz; 786 } 787 } 788 789 /** 790 * Creates a new public class. 791 * If there already exists a class with the same name, the new class 792 * overwrites that previous class. 793 * 794 * <p>If no constructor is explicitly added to the created new 795 * class, Javassist generates constructors and adds it when 796 * the class file is generated. It generates a new constructor 797 * for each constructor of the super class. The new constructor 798 * takes the same set of parameters and invokes the 799 * corresponding constructor of the super class. All the received 800 * parameters are passed to it. 801 * 802 * @param classname a fully-qualified class name. 803 * @throws RuntimeException if the existing class is frozen. 804 */ makeClass(String classname)805 public CtClass makeClass(String classname) throws RuntimeException { 806 return makeClass(classname, null); 807 } 808 809 /** 810 * Creates a new public class. 811 * If there already exists a class/interface with the same name, 812 * the new class overwrites that previous class. 813 * 814 * <p>If no constructor is explicitly added to the created new 815 * class, Javassist generates constructors and adds it when 816 * the class file is generated. It generates a new constructor 817 * for each constructor of the super class. The new constructor 818 * takes the same set of parameters and invokes the 819 * corresponding constructor of the super class. All the received 820 * parameters are passed to it. 821 * 822 * @param classname a fully-qualified class name. 823 * @param superclass the super class. 824 * @throws RuntimeException if the existing class is frozen. 825 */ makeClass(String classname, CtClass superclass)826 public synchronized CtClass makeClass(String classname, CtClass superclass) 827 throws RuntimeException 828 { 829 checkNotFrozen(classname); 830 CtClass clazz = new CtNewClass(classname, this, false, superclass); 831 cacheCtClass(classname, clazz, true); 832 return clazz; 833 } 834 835 /** 836 * Creates a new public nested class. 837 * This method is called by {@link CtClassType#makeNestedClass()}. 838 * 839 * @param classname a fully-qualified class name. 840 * @return the nested class. 841 */ makeNestedClass(String classname)842 synchronized CtClass makeNestedClass(String classname) { 843 checkNotFrozen(classname); 844 CtClass clazz = new CtNewClass(classname, this, false, null); 845 cacheCtClass(classname, clazz, true); 846 return clazz; 847 } 848 849 /** 850 * Creates a new public interface. 851 * If there already exists a class/interface with the same name, 852 * the new interface overwrites that previous one. 853 * 854 * @param name a fully-qualified interface name. 855 * @throws RuntimeException if the existing interface is frozen. 856 */ makeInterface(String name)857 public CtClass makeInterface(String name) throws RuntimeException { 858 return makeInterface(name, null); 859 } 860 861 /** 862 * Creates a new public interface. 863 * If there already exists a class/interface with the same name, 864 * the new interface overwrites that previous one. 865 * 866 * @param name a fully-qualified interface name. 867 * @param superclass the super interface. 868 * @throws RuntimeException if the existing interface is frozen. 869 */ makeInterface(String name, CtClass superclass)870 public synchronized CtClass makeInterface(String name, CtClass superclass) 871 throws RuntimeException 872 { 873 checkNotFrozen(name); 874 CtClass clazz = new CtNewClass(name, this, true, superclass); 875 cacheCtClass(name, clazz, true); 876 return clazz; 877 } 878 879 /** 880 * Creates a new annotation. 881 * If there already exists a class/interface with the same name, 882 * the new interface overwrites that previous one. 883 * 884 * @param name a fully-qualified interface name. 885 * Or null if the annotation has no super interface. 886 * @throws RuntimeException if the existing interface is frozen. 887 * @since 3.19 888 */ makeAnnotation(String name)889 public CtClass makeAnnotation(String name) throws RuntimeException { 890 try { 891 CtClass cc = makeInterface(name, get("java.lang.annotation.Annotation")); 892 cc.setModifiers(cc.getModifiers() | Modifier.ANNOTATION); 893 return cc; 894 } 895 catch (NotFoundException e) { 896 // should never happen. 897 throw new RuntimeException(e.getMessage(), e); 898 } 899 } 900 901 /** 902 * Appends the system search path to the end of the 903 * search path. The system search path 904 * usually includes the platform library, extension 905 * libraries, and the search path specified by the 906 * <code>-classpath</code> option or the <code>CLASSPATH</code> 907 * environment variable. 908 * 909 * @return the appended class path. 910 */ appendSystemPath()911 public ClassPath appendSystemPath() { 912 return source.appendSystemPath(); 913 } 914 915 /** 916 * Insert a <code>ClassPath</code> object at the head of the 917 * search path. 918 * 919 * @return the inserted class path. 920 * @see javassist.ClassPath 921 * @see javassist.URLClassPath 922 * @see javassist.ByteArrayClassPath 923 */ insertClassPath(ClassPath cp)924 public ClassPath insertClassPath(ClassPath cp) { 925 return source.insertClassPath(cp); 926 } 927 928 /** 929 * Appends a <code>ClassPath</code> object to the end of the 930 * search path. 931 * 932 * @return the appended class path. 933 * @see javassist.ClassPath 934 * @see javassist.URLClassPath 935 * @see javassist.ByteArrayClassPath 936 */ appendClassPath(ClassPath cp)937 public ClassPath appendClassPath(ClassPath cp) { 938 return source.appendClassPath(cp); 939 } 940 941 /** 942 * Inserts a directory or a jar (or zip) file at the head of the 943 * search path. 944 * 945 * @param pathname the path name of the directory or jar file. 946 * It must not end with a path separator ("/"). 947 * If the path name ends with "/*", then all the 948 * jar files matching the path name are inserted. 949 * 950 * @return the inserted class path. 951 * @throws NotFoundException if the jar file is not found. 952 */ insertClassPath(String pathname)953 public ClassPath insertClassPath(String pathname) 954 throws NotFoundException 955 { 956 return source.insertClassPath(pathname); 957 } 958 959 /** 960 * Appends a directory or a jar (or zip) file to the end of the 961 * search path. 962 * 963 * @param pathname the path name of the directory or jar file. 964 * It must not end with a path separator ("/"). 965 * If the path name ends with "/*", then all the 966 * jar files matching the path name are appended. 967 * 968 * @return the appended class path. 969 * @throws NotFoundException if the jar file is not found. 970 */ appendClassPath(String pathname)971 public ClassPath appendClassPath(String pathname) 972 throws NotFoundException 973 { 974 return source.appendClassPath(pathname); 975 } 976 977 /** 978 * Detatches the <code>ClassPath</code> object from the search path. 979 * The detached <code>ClassPath</code> object cannot be added 980 * to the path again. 981 */ removeClassPath(ClassPath cp)982 public void removeClassPath(ClassPath cp) { 983 source.removeClassPath(cp); 984 } 985 986 /** 987 * Appends directories and jar files for search. 988 * 989 * <p>The elements of the given path list must be separated by colons 990 * in Unix or semi-colons in Windows. 991 * 992 * @param pathlist a (semi)colon-separated list of 993 * the path names of directories and jar files. 994 * The directory name must not end with a path 995 * separator ("/"). 996 * @throws NotFoundException if a jar file is not found. 997 */ appendPathList(String pathlist)998 public void appendPathList(String pathlist) throws NotFoundException { 999 char sep = File.pathSeparatorChar; 1000 int i = 0; 1001 for (;;) { 1002 int j = pathlist.indexOf(sep, i); 1003 if (j < 0) { 1004 appendClassPath(pathlist.substring(i)); 1005 break; 1006 } 1007 else { 1008 appendClassPath(pathlist.substring(i, j)); 1009 i = j + 1; 1010 } 1011 } 1012 } 1013 1014 /** 1015 * Converts the given class to a <code>java.lang.Class</code> object. 1016 * Once this method is called, further modifications are not 1017 * allowed any more. 1018 * To load the class, this method uses the context class loader 1019 * of the current thread. It is obtained by calling 1020 * <code>getClassLoader()</code>. 1021 * 1022 * <p>This behavior can be changed by subclassing the pool and changing 1023 * the <code>getClassLoader()</code> method. 1024 * If the program is running on some application 1025 * server, the context class loader might be inappropriate to load the 1026 * class.</p> 1027 * 1028 * <p>This method is provided for convenience. If you need more 1029 * complex functionality, you should write your own class loader. 1030 * 1031 * <p><b>Warining:</b> 1032 * This method should not be used in Java 11 or later. 1033 * Use {@link #toClass(CtClass,Class)}. 1034 * </p> 1035 * 1036 * <p><b>Warining:</b> 1037 * A Class object returned by this method may not 1038 * work with a security manager or a signed jar file because a 1039 * protection domain is not specified.</p> 1040 * 1041 * @see #toClass(CtClass,Class) 1042 * @see #toClass(CtClass,Class,java.lang.ClassLoader,ProtectionDomain) 1043 * @see #getClassLoader() 1044 */ toClass(CtClass clazz)1045 public Class toClass(CtClass clazz) throws CannotCompileException { 1046 // Some subclasses of ClassPool may override toClass(CtClass,ClassLoader). 1047 // So we should call that method instead of toClass(.., ProtectionDomain). 1048 return toClass(clazz, getClassLoader()); 1049 } 1050 1051 /** 1052 * Get the classloader for <code>toClass()</code>, <code>getAnnotations()</code> in 1053 * <code>CtClass</code>, etc. 1054 * 1055 * <p>The default is the context class loader. 1056 * 1057 * @return the classloader for the pool 1058 * @see #toClass(CtClass) 1059 * @see CtClass#getAnnotations() 1060 */ getClassLoader()1061 public ClassLoader getClassLoader() { 1062 return getContextClassLoader(); 1063 } 1064 1065 /** 1066 * Obtains a class loader that seems appropriate to look up a class 1067 * by name. 1068 */ getContextClassLoader()1069 static ClassLoader getContextClassLoader() { 1070 return Thread.currentThread().getContextClassLoader(); 1071 } 1072 1073 /** 1074 * Converts the class to a <code>java.lang.Class</code> object. 1075 * Do not override this method any more at a subclass because 1076 * {@link #toClass(CtClass)} will never calls this method. 1077 * 1078 * <p><b>Warining:</b> A Class object returned by this method may not 1079 * work with a security manager or a signed jar file because a 1080 * protection domain is not specified. 1081 * 1082 * @deprecated Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}. 1083 * A subclass of <code>ClassPool</code> that has been 1084 * overriding this method should be modified. It should override 1085 * {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}. 1086 */ toClass(CtClass ct, ClassLoader loader)1087 public Class toClass(CtClass ct, ClassLoader loader) 1088 throws CannotCompileException 1089 { 1090 return toClass(ct, null, loader, null); 1091 } 1092 1093 /** 1094 * Converts the class to a <code>java.lang.Class</code> object. 1095 * Once this method is called, further modifications are not allowed 1096 * any more. 1097 * 1098 * <p>The class file represented by the given <code>CtClass</code> is 1099 * loaded by the given class loader to construct a 1100 * <code>java.lang.Class</code> object. Since a private method 1101 * on the class loader is invoked through the reflection API, 1102 * the caller must have permissions to do that.</p> 1103 * 1104 * <p>An easy way to obtain <code>ProtectionDomain</code> object is 1105 * to call <code>getProtectionDomain()</code> 1106 * in <code>java.lang.Class</code>. It returns the domain that the 1107 * class belongs to. 1108 * 1109 * <p>This method is provided for convenience. If you need more 1110 * complex functionality, you should write your own class loader.</p> 1111 * 1112 * @param ct the class converted into {@code java.lang.Class}. 1113 * @param loader the class loader used to load this class. 1114 * For example, the loader returned by 1115 * <code>getClassLoader()</code> can be used 1116 * for this parameter. 1117 * @param domain the protection domain for the class. 1118 * If it is null, the default domain created 1119 * by <code>java.lang.ClassLoader</code> is used. 1120 * 1121 * @see #getClassLoader() 1122 * @since 3.3 1123 * @deprecated Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}. 1124 */ toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)1125 public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) 1126 throws CannotCompileException 1127 { 1128 return toClass(ct, null, loader, domain); 1129 } 1130 1131 /** 1132 * Converts the class to a <code>java.lang.Class</code> object. 1133 * Once this method is called, further modifications are not allowed 1134 * any more. 1135 * 1136 * <p>This method is available in Java 9 or later. 1137 * It loads the class 1138 * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}. 1139 * </p> 1140 * 1141 * @param ct the class converted into {@code java.lang.Class}. 1142 * @param neighbor a class belonging to the same package that 1143 * the converted class belongs to. 1144 * @since 3.24 1145 */ toClass(CtClass ct, Class<?> neighbor)1146 public Class<?> toClass(CtClass ct, Class<?> neighbor) 1147 throws CannotCompileException 1148 { 1149 try { 1150 return javassist.util.proxy.DefineClassHelper.toClass(neighbor, 1151 ct.toBytecode()); 1152 } 1153 catch (IOException e) { 1154 throw new CannotCompileException(e); 1155 } 1156 } 1157 1158 /** 1159 * Converts the class to a <code>java.lang.Class</code> object. 1160 * Once this method is called, further modifications are not allowed 1161 * any more. 1162 * 1163 * <p>This method is available in Java 9 or later. 1164 * It loads the class 1165 * by using the given {@code java.lang.invoke.MethodHandles.Lookup}. 1166 * </p> 1167 * 1168 * @param ct the class converted into {@code java.lang.Class}. 1169 * @since 3.24 1170 */ toClass(CtClass ct, java.lang.invoke.MethodHandles.Lookup lookup)1171 public Class<?> toClass(CtClass ct, 1172 java.lang.invoke.MethodHandles.Lookup lookup) 1173 throws CannotCompileException 1174 { 1175 try { 1176 return javassist.util.proxy.DefineClassHelper.toClass(lookup, 1177 ct.toBytecode()); 1178 } 1179 catch (IOException e) { 1180 throw new CannotCompileException(e); 1181 } 1182 } 1183 1184 /** 1185 * Converts the class to a <code>java.lang.Class</code> object. 1186 * Once this method is called, further modifications are not allowed 1187 * any more. 1188 * 1189 * <p>When the JVM is Java 11 or later, this method loads the class 1190 * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}. 1191 * The other arguments {@code loader} and {@code domain} are not used; 1192 * so they can be null. 1193 * </p> 1194 * 1195 * <p>Otherwise, or when {@code neighbor} is null, 1196 * the class file represented by the given <code>CtClass</code> is 1197 * loaded by the given class loader to construct a 1198 * <code>java.lang.Class</code> object. Since a private method 1199 * on the class loader is invoked through the reflection API, 1200 * the caller must have permissions to do that. 1201 * 1202 * <p>An easy way to obtain <code>ProtectionDomain</code> object is 1203 * to call <code>getProtectionDomain()</code> 1204 * in <code>java.lang.Class</code>. It returns the domain that the 1205 * class belongs to. 1206 * 1207 * <p>If your program is for only Java 9 or later, don't use this method. 1208 * Use {@link #toClass(CtClass,Class)} or 1209 * {@link #toClass(CtClass,java.lang.invoke.MethodHandles.Lookup)}. 1210 * </p> 1211 * 1212 * @param ct the class converted into {@code java.lang.Class}. 1213 * @param neighbor a class belonging to the same package that 1214 * the converted class belongs to. 1215 * It can be null. 1216 * @param loader the class loader used to load this class. 1217 * For example, the loader returned by 1218 * <code>getClassLoader()</code> can be used 1219 * for this parameter. 1220 * @param domain the protection domain for the class. 1221 * If it is null, the default domain created 1222 * by <code>java.lang.ClassLoader</code> is used. 1223 * 1224 * @see #getClassLoader() 1225 * @since 3.24 1226 */ toClass(CtClass ct, Class<?> neighbor, ClassLoader loader, ProtectionDomain domain)1227 public Class toClass(CtClass ct, Class<?> neighbor, ClassLoader loader, 1228 ProtectionDomain domain) 1229 throws CannotCompileException 1230 { 1231 try { 1232 return javassist.util.proxy.DefineClassHelper.toClass(ct.getName(), 1233 neighbor, loader, domain, ct.toBytecode()); 1234 } 1235 catch (IOException e) { 1236 throw new CannotCompileException(e); 1237 } 1238 } 1239 1240 /** 1241 * Defines a new package. If the package is already defined, this method 1242 * performs nothing. 1243 * 1244 * <p>You do not necessarily need to 1245 * call this method. If this method is called, then 1246 * <code>getPackage()</code> on the <code>Class</code> object returned 1247 * by <code>toClass()</code> will return a non-null object.</p> 1248 * 1249 * <p>The jigsaw module introduced by Java 9 has broken this method. 1250 * In Java 9 or later, the VM argument 1251 * <code>--add-opens java.base/java.lang=ALL-UNNAMED</code> 1252 * has to be given to the JVM so that this method can run. 1253 * </p> 1254 * 1255 * @param loader the class loader passed to <code>toClass()</code> or 1256 * the default one obtained by <code>getClassLoader()</code>. 1257 * @param name the package name. 1258 * @see #getClassLoader() 1259 * @see #toClass(CtClass) 1260 * @see CtClass#toClass() 1261 * @since 3.16 1262 * @deprecated 1263 */ makePackage(ClassLoader loader, String name)1264 public void makePackage(ClassLoader loader, String name) 1265 throws CannotCompileException 1266 { 1267 DefinePackageHelper.definePackage(name, loader); 1268 } 1269 1270 } 1271