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