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