KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > ClassPool


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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 JavaDoc;
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.Hashtable JavaDoc;
25
26 /**
27  * A container of <code>CtClass</code> objects.
28  * A <code>CtClass</code> object must be obtained from this object.
29  * If <code>get()</code> is called on this object,
30  * it searches various sources represented by <code>ClassPath</code>
31  * to find a class file and then it creates a <code>CtClass</code> object
32  * representing that class file. The created object is returned to the
33  * caller.
34  *
35  * <p><b>Memory consumption memo:</b>
36  *
37  * <p><code>ClassPool</code> objects hold all the <code>CtClass</code>es
38  * that have been created so that the consistency among modified classes
39  * can be guaranteed. Thus if a large number of <code>CtClass</code>es
40  * are processed, the <code>ClassPool</code> will consume a huge amount
41  * of memory. To avoid this, a <code>ClassPool</code> object
42  * should be recreated, for example, every hundred classes processed.
43  * Note that <code>getDefault()</code> is a singleton factory.
44  * Otherwise, <code>detach()</code> in <code>CtClass</code> should be used
45  * to avoid huge memory consumption.
46  *
47  * <p><b><code>ClassPool</code> hierarchy:</b>
48  *
49  * <p><code>ClassPool</code>s can make a parent-child hierarchy as
50  * <code>java.lang.ClassLoader</code>s. If a <code>ClassPool</code> has
51  * a parent pool, <code>get()</code> first asks the parent pool to find
52  * a class file. Only if the parent could not find the class file,
53  * <code>get()</code> searches the <code>ClassPath</code>s of
54  * the child <code>ClassPool</code>. This search order is reversed if
55  * <code>ClassPath.childFirstLookup</code> is <code>true</code>.
56  *
57  * @see javassist.CtClass
58  * @see javassist.ClassPath
59  */

60 public class ClassPool {
61
62     /**
63      * Determines the search order.
64      *
65      * <p>If this field is true, <code>get()</code> first searches the
66      * class path associated to this <code>ClassPool</code> and then
67      * the class path associated with the parent <code>ClassPool</code>.
68      * Otherwise, the class path associated with the parent is searched
69      * first.
70      *
71      * <p>The default value is false.
72      */

73     public boolean childFirstLookup = false;
74
75     protected ClassPoolTail source;
76     protected ClassPool parent;
77     protected Hashtable JavaDoc classes; // should be synchronous
78

79     /**
80      * Table of registered cflow variables.
81      */

82     private Hashtable JavaDoc cflow = null; // should be synchronous.
83

84     private static final int INIT_HASH_SIZE = 191;
85
86     /**
87      * Creates a root class pool. No parent class pool is specified.
88      */

89     public ClassPool() {
90         this(null);
91     }
92
93     /**
94      * Creates a class pool.
95      *
96      * @param parent the parent of this class pool. If this is a root
97      * class pool, this parameter must be <code>null</code>.
98      * @see javassist.ClassPool#getDefault()
99      */

100     public ClassPool(ClassPool parent) {
101         this.classes = new Hashtable JavaDoc(INIT_HASH_SIZE);
102         this.source = new ClassPoolTail();
103         this.parent = parent;
104         if (parent == null) {
105             CtClass[] pt = CtClass.primitiveTypes;
106             for (int i = 0; i < pt.length; ++i)
107                 classes.put(pt[i].getName(), pt[i]);
108         }
109
110         this.cflow = null;
111     }
112
113     /**
114      * Returns the default class pool.
115      * The returned object is always identical since this method is
116      * a singleton factory.
117      *
118      * <p>The default class pool searches the system search path,
119      * which usually includes the platform library, extension
120      * libraries, and the search path specified by the
121      * <code>-classpath</code> option or the <code>CLASSPATH</code>
122      * environment variable.
123      *
124      * <p>When this method is called for the first time, the default
125      * class pool is created with the following code snippet:
126      *
127      * <ul><code>ClassPool cp = new ClassPool();
128      * cp.appendSystemPath();
129      * </code></ul>
130      *
131      * <p>If the default class pool cannot find any class files,
132      * try <code>ClassClassPath</code> and <code>LoaderClassPath</code>.
133      *
134      * @see ClassClassPath
135      * @see LoaderClassPath
136      */

137     public static synchronized ClassPool getDefault() {
138         if (defaultPool == null) {
139             defaultPool = new ClassPool(null);
140             defaultPool.appendSystemPath();
141         }
142
143         return defaultPool;
144     }
145
146     private static ClassPool defaultPool = null;
147
148     /**
149      * Provide a hook so that subclasses can do their own
150      * caching of classes.
151      *
152      * @see #cacheCtClass(String,CtClass)
153      * @see #removeCached(String)
154      */

155     protected CtClass getCached(String JavaDoc classname) {
156         return (CtClass)classes.get(classname);
157     }
158
159     /**
160      * Provides a hook so that subclasses can do their own
161      * caching of classes.
162      *
163      * @see #getCached(String)
164      * @see #removeCached(String,CtClass)
165      */

166     protected void cacheCtClass(String JavaDoc classname, CtClass c) {
167         classes.put(classname, c);
168     }
169
170     /**
171      * Provide a hook so that subclasses can do their own
172      * caching of classes.
173      *
174      * @see #getCached(String)
175      * @see #cacheCtClass(String,CtClass)
176      */

177     protected CtClass removeCached(String JavaDoc classname) {
178         return (CtClass)classes.remove(classname);
179     }
180
181     /**
182      * Returns the class search path.
183      */

184     public String JavaDoc toString() {
185         return source.toString();
186     }
187
188     /**
189      * Records a name that never exists.
190      * For example, a package name can be recorded by this method.
191      * This would improve execution performance
192      * since <code>get()</code> does not search the class path at all
193      * if the given name is an invalid name recorded by this method.
194      * Note that searching the class path takes relatively long time.
195      *
196      * @param name a class name (separeted by dot).
197      */

198     public void recordInvalidClassName(String JavaDoc name) {
199         source.recordInvalidClassName(name);
200     }
201
202     /**
203      * Records the <code>$cflow</code> variable for the field specified
204      * by <code>cname</code> and <code>fname</code>.
205      *
206      * @param name variable name
207      * @param cname class name
208      * @param fname field name
209      */

210     void recordCflow(String JavaDoc name, String JavaDoc cname, String JavaDoc fname) {
211         if (cflow == null)
212             cflow = new Hashtable JavaDoc();
213
214         cflow.put(name, new Object JavaDoc[] { cname, fname });
215     }
216
217     /**
218      * Undocumented method. Do not use; internal-use only.
219      *
220      * @param name the name of <code>$cflow</code> variable
221      */

222     public Object JavaDoc[] lookupCflow(String JavaDoc name) {
223         if (cflow == null)
224             cflow = new Hashtable JavaDoc();
225
226         return (Object JavaDoc[])cflow.get(name);
227     }
228
229     /**
230      * Reads a class file and constructs a <code>CtClass</code>
231      * object with a new name.
232      * This method is useful if you want to generate a new class as a copy
233      * of another class (except the class name). For example,
234      *
235      * <ul><pre>
236      * getAndRename("Point", "Pair")
237      * </pre></ul>
238      *
239      * returns a <code>CtClass</code> object representing <code>Pair</code>
240      * class. The definition of <code>Pair</code> is the same as that of
241      * <code>Point</code> class except the class name since <code>Pair</code>
242      * is defined by reading <code>Point.class</code>.
243      *
244      * @param orgName the original (fully-qualified) class name
245      * @param newName the new class name
246      */

247     public CtClass getAndRename(String JavaDoc orgName, String JavaDoc newName)
248         throws NotFoundException
249     {
250         CtClass clazz = get0(orgName, false);
251         if (clazz == null)
252             throw new NotFoundException(orgName);
253
254         if (clazz instanceof CtClassType)
255             ((CtClassType)clazz).setClassPool(this);
256
257         clazz.setName(newName); // indirectly calls
258
// classNameChanged() in this class
259
return clazz;
260     }
261
262     /*
263      * This method is invoked by CtClassType.setName(). It removes a
264      * CtClass object from the hash table and inserts it with the new
265      * name. Don't delegate to the parent.
266      */

267     synchronized void classNameChanged(String JavaDoc oldname, CtClass clazz) {
268         CtClass c = (CtClass)getCached(oldname);
269         if (c == clazz) // must check this equation.
270
removeCached(oldname); // see getAndRename().
271

272         String JavaDoc newName = clazz.getName();
273         checkNotFrozen(newName);
274         cacheCtClass(newName, clazz);
275     }
276
277     /**
278      * Reads a class file from the source and returns a reference
279      * to the <code>CtClass</code>
280      * object representing that class file. If that class file has been
281      * already read, this method returns a reference to the
282      * <code>CtClass</code> created when that class file was read at the
283      * first time.
284      *
285      * <p>If <code>classname</code> ends with "[]", then this method
286      * returns a <code>CtClass</code> object for that array type.
287      *
288      * <p>To obtain an inner class, use "$" instead of "." for separating
289      * the enclosing class name and the inner class name.
290      *
291      * @param classname a fully-qualified class name.
292      */

293     public CtClass get(String JavaDoc classname) throws NotFoundException {
294         CtClass clazz;
295         if (classname == null)
296             clazz = null;
297         else
298             clazz = get0(classname, true);
299
300         if (clazz == null)
301             throw new NotFoundException(classname);
302         else {
303             clazz.incGetCounter();
304             return clazz;
305         }
306     }
307
308     /**
309      * @param useCache false if the cached CtClass must be ignored.
310      * @param searchParent false if the parent class pool is not searched.
311      * @return null if the class could not be found.
312      */

313     protected synchronized CtClass get0(String JavaDoc classname, boolean useCache)
314         throws NotFoundException
315     {
316         CtClass clazz = null;
317         if (useCache) {
318             clazz = getCached(classname);
319             if (clazz != null)
320                 return clazz;
321         }
322
323         if (!childFirstLookup && parent != null) {
324             clazz = parent.get0(classname, useCache);
325             if (clazz != null)
326                 return clazz;
327         }
328
329         clazz = createCtClass(classname, useCache);
330         if (clazz != null) {
331             if (useCache)
332                 cacheCtClass(classname, clazz);
333
334             return clazz;
335         }
336
337         if (childFirstLookup && parent != null)
338             clazz = parent.get0(classname, useCache);
339
340         return clazz;
341     }
342
343     /**
344      * Creates a CtClass object representing the specified class.
345      * It first examines whether or not the corresponding class
346      * file exists. If yes, it creates a CtClass object.
347      *
348      * @return null if the class file could not be found.
349      */

350     protected CtClass createCtClass(String JavaDoc classname, boolean useCache) {
351         if (classname.endsWith("[]")) {
352             String JavaDoc base = classname.substring(0, classname.indexOf('['));
353             if ((!useCache || getCached(base) == null) && find(base) == null)
354                 return null;
355             else
356                 return new CtArray(classname, this);
357         }
358         else
359             if (find(classname) == null)
360                 return null;
361             else
362                 return new CtClassType(classname, this);
363     }
364
365     /**
366      * Searches the class path to obtain the URL of the class file
367      * specified by classname. It is also used to determine whether
368      * the class file exists.
369      *
370      * @param classname a fully-qualified class name.
371      * @return null if the class file could not be found.
372      * @see CtClass#getURL()
373      */

374     public URL JavaDoc find(String JavaDoc classname) {
375         return source.find(classname);
376     }
377
378     /*
379      * Is invoked by CtClassType.setName() and methods in this class.
380      * This method throws an exception if the class is already frozen or
381      * if this class pool cannot edit the class since it is in a parent
382      * class pool.
383      */

384     void checkNotFrozen(String JavaDoc classname) throws RuntimeException JavaDoc {
385         CtClass clazz = getCached(classname);
386         if (clazz == null) {
387             if (!childFirstLookup && parent != null) {
388                 try {
389                     clazz = parent.get0(classname, true);
390                 }
391                 catch (NotFoundException e) {}
392                 if (clazz != null)
393                     throw new RuntimeException JavaDoc(classname
394                             + " is in a parent ClassPool. Use the parent.");
395             }
396         }
397         else
398             if (clazz.isFrozen())
399                 throw new RuntimeException JavaDoc(classname
400                                         + ": frozen class (cannot edit)");
401     }
402
403     /* for CtClassType.getClassFile2(). Don't delegate to the parent.
404      */

405     InputStream JavaDoc openClassfile(String JavaDoc classname) throws NotFoundException {
406         return source.openClassfile(classname);
407     }
408
409     void writeClassfile(String JavaDoc classname, OutputStream JavaDoc out)
410         throws NotFoundException, IOException JavaDoc, CannotCompileException
411     {
412         source.writeClassfile(classname, out);
413     }
414
415     /**
416      * Reads class files from the source and returns an array of
417      * <code>CtClass</code>
418      * objects representing those class files.
419      *
420      * <p>If an element of <code>classnames</code> ends with "[]",
421      * then this method
422      * returns a <code>CtClass</code> object for that array type.
423      *
424      * @param classnames an array of fully-qualified class name.
425      */

426     public CtClass[] get(String JavaDoc[] classnames) throws NotFoundException {
427         if (classnames == null)
428             return new CtClass[0];
429
430         int num = classnames.length;
431         CtClass[] result = new CtClass[num];
432         for (int i = 0; i < num; ++i)
433             result[i] = get(classnames[i]);
434
435         return result;
436     }
437
438     /**
439      * Reads a class file and obtains a compile-time method.
440      *
441      * @param classname the class name
442      * @param methodname the method name
443      * @see CtClass#getDeclaredMethod(String)
444      */

445     public CtMethod getMethod(String JavaDoc classname, String JavaDoc methodname)
446         throws NotFoundException
447     {
448         CtClass c = get(classname);
449         return c.getDeclaredMethod(methodname);
450     }
451
452     /**
453      * Creates a new class (or interface) from the given class file.
454      * If there already exists a class with the same name, the new class
455      * overwrites that previous class.
456      *
457      * <p>This method is used for creating a <code>CtClass</code> object
458      * directly from a class file. The qualified class name is obtained
459      * from the class file; you do not have to explicitly give the name.
460      *
461      * @param classfile class file.
462      * @throws RuntimeException if there is a frozen class with the
463      * the same name.
464      * @see javassist.ByteArrayClassPath
465      */

466     public CtClass makeClass(InputStream JavaDoc classfile)
467         throws IOException JavaDoc, RuntimeException JavaDoc {
468         classfile = new BufferedInputStream JavaDoc(classfile);
469         CtClass clazz = new CtClassType(classfile, this);
470         clazz.checkModify();
471         String JavaDoc classname = clazz.getName();
472         checkNotFrozen(classname);
473         cacheCtClass(classname, clazz);
474         return clazz;
475     }
476
477     /**
478      * Creates a new public class.
479      * If there already exists a class with the same name, the new class
480      * overwrites that previous class.
481      *
482      * @param classname a fully-qualified class name.
483      * @throws RuntimeException if the existing class is frozen.
484      */

485     public CtClass makeClass(String JavaDoc classname) throws RuntimeException JavaDoc {
486         return makeClass(classname, null);
487     }
488
489     /**
490      * Creates a new public class.
491      * If there already exists a class/interface with the same name,
492      * the new class overwrites that previous class.
493      *
494      * @param classname a fully-qualified class name.
495      * @param superclass the super class.
496      * @throws RuntimeException if the existing class is frozen.
497      */

498     public synchronized CtClass makeClass(String JavaDoc classname, CtClass superclass)
499         throws RuntimeException JavaDoc
500     {
501         checkNotFrozen(classname);
502         CtClass clazz = new CtNewClass(classname, this, false, superclass);
503         cacheCtClass(classname, clazz);
504         return clazz;
505     }
506
507     /**
508      * Creates a new nested class.
509      * This method is called by CtClassType.makeNestedClass().
510      *
511      * @param classname a fully-qualified class name.
512      * @return the nested class.
513      */

514     synchronized CtClass makeNestedClass(String JavaDoc classname) {
515         checkNotFrozen(classname);
516         CtClass clazz = new CtNewNestedClass(classname, this, false, null);
517         cacheCtClass(classname, clazz);
518         return clazz;
519     }
520
521     /**
522      * Creates a new public interface.
523      * If there already exists a class/interface with the same name,
524      * the new interface overwrites that previous one.
525      *
526      * @param name a fully-qualified interface name.
527      * @throws RuntimeException if the existing interface is frozen.
528      */

529     public CtClass makeInterface(String JavaDoc name) throws RuntimeException JavaDoc {
530         return makeInterface(name, null);
531     }
532
533     /**
534      * Creates a new public interface.
535      * If there already exists a class/interface with the same name,
536      * the new interface overwrites that previous one.
537      *
538      * @param name a fully-qualified interface name.
539      * @param superclass the super interface.
540      * @throws RuntimeException if the existing interface is frozen.
541      */

542     public synchronized CtClass makeInterface(String JavaDoc name, CtClass superclass)
543         throws RuntimeException JavaDoc
544     {
545         checkNotFrozen(name);
546         CtClass clazz = new CtNewClass(name, this, true, superclass);
547         cacheCtClass(name, clazz);
548         return clazz;
549     }
550
551     /**
552      * Appends the system search path to the end of the
553      * search path. The system search path
554      * usually includes the platform library, extension
555      * libraries, and the search path specified by the
556      * <code>-classpath</code> option or the <code>CLASSPATH</code>
557      * environment variable.
558      *
559      * @return the appended class path.
560      */

561     public ClassPath appendSystemPath() {
562         return source.appendSystemPath();
563     }
564
565     /**
566      * Insert a <code>ClassPath</code> object at the head of the
567      * search path.
568      *
569      * @return the inserted class path.
570      * @see javassist.ClassPath
571      * @see javassist.URLClassPath
572      * @see javassist.ByteArrayClassPath
573      */

574     public ClassPath insertClassPath(ClassPath cp) {
575         return source.insertClassPath(cp);
576     }
577
578     /**
579      * Appends a <code>ClassPath</code> object to the end of the
580      * search path.
581      *
582      * @return the appended class path.
583      * @see javassist.ClassPath
584      * @see javassist.URLClassPath
585      * @see javassist.ByteArrayClassPath
586      */

587     public ClassPath appendClassPath(ClassPath cp) {
588         return source.appendClassPath(cp);
589     }
590
591     /**
592      * Inserts a directory or a jar (or zip) file at the head of the
593      * search path.
594      *
595      * @param pathname the path name of the directory or jar file.
596      * It must not end with a path separator ("/").
597      * @return the inserted class path.
598      * @throws NotFoundException if the jar file is not found.
599      */

600     public ClassPath insertClassPath(String JavaDoc pathname)
601         throws NotFoundException
602     {
603         return source.insertClassPath(pathname);
604     }
605
606     /**
607      * Appends a directory or a jar (or zip) file to the end of the
608      * search path.
609      *
610      * @param pathname the path name of the directory or jar file.
611      * It must not end with a path separator ("/").
612      * @return the appended class path.
613      * @throws NotFoundException if the jar file is not found.
614      */

615     public ClassPath appendClassPath(String JavaDoc pathname)
616         throws NotFoundException
617     {
618         return source.appendClassPath(pathname);
619     }
620
621     /**
622      * Detatches the <code>ClassPath</code> object from the search path.
623      * The detached <code>ClassPath</code> object cannot be added
624      * to the pathagain.
625      */

626     public void removeClassPath(ClassPath cp) {
627         source.removeClassPath(cp);
628     }
629
630     /**
631      * Appends directories and jar files for search.
632      *
633      * <p>The elements of the given path list must be separated by colons
634      * in Unix or semi-colons in Windows.
635      *
636      * @param pathlist a (semi)colon-separated list of
637      * the path names of directories and jar files.
638      * The directory name must not end with a path
639      * separator ("/").
640      * @throws NotFoundException if a jar file is not found.
641      */

642     public void appendPathList(String JavaDoc pathlist) throws NotFoundException {
643         char sep = File.pathSeparatorChar;
644         int i = 0;
645         for (;;) {
646             int j = pathlist.indexOf(sep, i);
647             if (j < 0) {
648                 appendClassPath(pathlist.substring(i));
649                 break;
650             }
651             else {
652                 appendClassPath(pathlist.substring(i, j));
653                 i = j + 1;
654             }
655         }
656     }
657
658     /**
659      * Converts the given class to a <code>java.lang.Class</code> object.
660      * Once this method is called, further modifications are not
661      * allowed any more.
662      * To load the class, this method uses the context class loader
663      * of the current thread. If the program is running on some application
664      * server, the context class loader might be inappropriate to load the
665      * class.
666      *
667      * <p>This method is provided for convenience. If you need more
668      * complex functionality, you should write your own class loader.
669      *
670      * @see #toClass(CtClass, java.lang.ClassLoader)
671      */

672     public Class JavaDoc toClass(CtClass clazz) throws CannotCompileException {
673         return toClass(clazz, Thread.currentThread().getContextClassLoader());
674     }
675
676     /**
677      * Converts the class to a <code>java.lang.Class</code> object.
678      * Once this method is called, further modifications are not allowed
679      * any more.
680      *
681      * <p>The class file represented by the given <code>CtClass</code> is
682      * loaded by the given class loader to construct a
683      * <code>java.lang.Class</code> object. Since a private method
684      * on the class loader is invoked through the reflection API,
685      * the caller must have permissions to do that.
686      *
687      * <p>This method is provided for convenience. If you need more
688      * complex functionality, you should write your own class loader.
689      *
690      * @param loader the class loader used to load this class.
691      */

692     public Class JavaDoc toClass(CtClass ct, ClassLoader JavaDoc loader)
693         throws CannotCompileException
694     {
695         try {
696             byte[] b = ct.toBytecode();
697             Class JavaDoc cl = Class.forName("java.lang.ClassLoader");
698             java.lang.reflect.Method JavaDoc method =
699                 cl.getDeclaredMethod("defineClass",
700                                 new Class JavaDoc[] { String JavaDoc.class, byte[].class,
701                                               int.class, int.class });
702             method.setAccessible(true);
703             Object JavaDoc[] args = new Object JavaDoc[] { ct.getName(), b, new Integer JavaDoc(0),
704                                            new Integer JavaDoc(b.length)};
705             Class JavaDoc clazz = (Class JavaDoc)method.invoke(loader, args);
706             method.setAccessible(false);
707             return clazz;
708         }
709         catch (RuntimeException JavaDoc e) {
710             throw e;
711         }
712         catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
713             throw new CannotCompileException(e.getTargetException());
714         }
715         catch (Exception JavaDoc e) {
716             throw new CannotCompileException(e);
717         }
718     }
719 }
720
Popular Tags