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