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
16package javassist;
17
18import java.io.BufferedInputStream;
19import java.io.File;
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.OutputStream;
23import java.lang.reflect.Method;
24import java.net.URL;
25import java.security.AccessController;
26import java.security.PrivilegedActionException;
27import java.security.PrivilegedExceptionAction;
28import java.security.ProtectionDomain;
29import java.util.Hashtable;
30import java.util.Iterator;
31import java.util.ArrayList;
32import java.util.Enumeration;
33import 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 */
69public 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