Home | History | Annotate | Download | only in javassist
      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 {
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    259     protected CtClass removeCached(String classname) {
    260         return (CtClass)classes.remove(classname);
    261     }
    262 
    263     /**
    264      * Returns the class search path.
    265      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    630     InputStream openClassfile(String classname) throws NotFoundException {
    631         return source.openClassfile(classname);
    632     }
    633 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
   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      */
   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      */
   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      */
   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 
   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