001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist;
017:
018: import java.io.BufferedInputStream;
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.OutputStream;
023: import java.lang.reflect.Method;
024: import java.net.URL;
025: import java.security.AccessController;
026: import java.security.PrivilegedActionException;
027: import java.security.PrivilegedExceptionAction;
028: import java.security.ProtectionDomain;
029: import java.util.Hashtable;
030: import java.util.Iterator;
031: import java.util.ArrayList;
032: import javassist.bytecode.Descriptor;
033:
034: /**
035: * A container of <code>CtClass</code> objects.
036: * A <code>CtClass</code> object must be obtained from this object.
037: * If <code>get()</code> is called on this object,
038: * it searches various sources represented by <code>ClassPath</code>
039: * to find a class file and then it creates a <code>CtClass</code> object
040: * representing that class file. The created object is returned to the
041: * caller.
042: *
043: * <p><b>Memory consumption memo:</b>
044: *
045: * <p><code>ClassPool</code> objects hold all the <code>CtClass</code>es
046: * that have been created so that the consistency among modified classes
047: * can be guaranteed. Thus if a large number of <code>CtClass</code>es
048: * are processed, the <code>ClassPool</code> will consume a huge amount
049: * of memory. To avoid this, a <code>ClassPool</code> object
050: * should be recreated, for example, every hundred classes processed.
051: * Note that <code>getDefault()</code> is a singleton factory.
052: * Otherwise, <code>detach()</code> in <code>CtClass</code> should be used
053: * to avoid huge memory consumption.
054: *
055: * <p><b><code>ClassPool</code> hierarchy:</b>
056: *
057: * <p><code>ClassPool</code>s can make a parent-child hierarchy as
058: * <code>java.lang.ClassLoader</code>s. If a <code>ClassPool</code> has
059: * a parent pool, <code>get()</code> first asks the parent pool to find
060: * a class file. Only if the parent could not find the class file,
061: * <code>get()</code> searches the <code>ClassPath</code>s of
062: * the child <code>ClassPool</code>. This search order is reversed if
063: * <code>ClassPath.childFirstLookup</code> is <code>true</code>.
064: *
065: * @see javassist.CtClass
066: * @see javassist.ClassPath
067: */
068: public class ClassPool {
069: // used by toClass().
070: private static java.lang.reflect.Method defineClass1, defineClass2;
071:
072: static {
073: try {
074: AccessController
075: .doPrivileged(new PrivilegedExceptionAction() {
076: public Object run() throws Exception {
077: Class cl = Class
078: .forName("java.lang.ClassLoader");
079: defineClass1 = cl.getDeclaredMethod(
080: "defineClass", new Class[] {
081: String.class, byte[].class,
082: int.class, int.class });
083:
084: defineClass2 = cl.getDeclaredMethod(
085: "defineClass", new Class[] {
086: String.class, byte[].class,
087: int.class, int.class,
088: ProtectionDomain.class });
089: return null;
090: }
091: });
092: } catch (PrivilegedActionException pae) {
093: throw new RuntimeException("cannot initialize ClassPool",
094: pae.getException());
095: }
096: }
097:
098: /**
099: * Determines the search order.
100: *
101: * <p>If this field is true, <code>get()</code> first searches the
102: * class path associated to this <code>ClassPool</code> and then
103: * the class path associated with the parent <code>ClassPool</code>.
104: * Otherwise, the class path associated with the parent is searched
105: * first.
106: *
107: * <p>The default value is false.
108: */
109: public boolean childFirstLookup = false;
110:
111: /**
112: * Turning the automatic pruning on/off.
113: *
114: * <p>If this field is true, <code>CtClass</code> objects are
115: * automatically pruned by default when <code>toBytecode()</code> etc.
116: * are called. The automatic pruning can be turned on/off individually
117: * for each <code>CtClass</code> object.
118: *
119: * <p>The initial value is true.
120: *
121: * @see CtClass#prune()
122: * @see CtClass#stopPruning(boolean)
123: */
124: public static boolean doPruning = true;
125:
126: /* releaseUnmodifiedClassFile was introduced for avoiding a bug
127: of JBoss AOP. So the value should be true except for JBoss AOP.
128: */
129:
130: /**
131: * If true, unmodified and not-recently-used class files are
132: * periodically released for saving memory.
133: *
134: * <p>The initial value is true.
135: */
136: public static boolean releaseUnmodifiedClassFile = true;
137:
138: protected ClassPoolTail source;
139: protected ClassPool parent;
140: protected Hashtable classes; // should be synchronous
141:
142: /**
143: * Table of registered cflow variables.
144: */
145: private Hashtable cflow = null; // should be synchronous.
146:
147: private static final int INIT_HASH_SIZE = 191;
148:
149: private ArrayList importedPackages;
150:
151: /**
152: * Creates a root class pool. No parent class pool is specified.
153: */
154: public ClassPool() {
155: this (null);
156: }
157:
158: /**
159: * Creates a root class pool. If <code>useDefaultPath</code> is
160: * true, <code>appendSystemPath()</code> is called. Otherwise,
161: * this constructor is equivalent to the constructor taking no
162: * parameter.
163: *
164: * @param useDefaultPath true if the system search path is
165: * appended.
166: */
167: public ClassPool(boolean useDefaultPath) {
168: this (null);
169: if (useDefaultPath)
170: appendSystemPath();
171: }
172:
173: /**
174: * Creates a class pool.
175: *
176: * @param parent the parent of this class pool. If this is a root
177: * class pool, this parameter must be <code>null</code>.
178: * @see javassist.ClassPool#getDefault()
179: */
180: public ClassPool(ClassPool parent) {
181: this .classes = new Hashtable(INIT_HASH_SIZE);
182: this .source = new ClassPoolTail();
183: this .parent = parent;
184: if (parent == null) {
185: CtClass[] pt = CtClass.primitiveTypes;
186: for (int i = 0; i < pt.length; ++i)
187: classes.put(pt[i].getName(), pt[i]);
188: }
189:
190: this .cflow = null;
191: clearImportedPackages();
192: }
193:
194: /**
195: * Returns the default class pool.
196: * The returned object is always identical since this method is
197: * a singleton factory.
198: *
199: * <p>The default class pool searches the system search path,
200: * which usually includes the platform library, extension
201: * libraries, and the search path specified by the
202: * <code>-classpath</code> option or the <code>CLASSPATH</code>
203: * environment variable.
204: *
205: * <p>When this method is called for the first time, the default
206: * class pool is created with the following code snippet:
207: *
208: * <ul><code>ClassPool cp = new ClassPool();
209: * cp.appendSystemPath();
210: * </code></ul>
211: *
212: * <p>If the default class pool cannot find any class files,
213: * try <code>ClassClassPath</code> and <code>LoaderClassPath</code>.
214: *
215: * @see ClassClassPath
216: * @see LoaderClassPath
217: */
218: public static synchronized ClassPool getDefault() {
219: if (defaultPool == null) {
220: defaultPool = new ClassPool(null);
221: defaultPool.appendSystemPath();
222: }
223:
224: return defaultPool;
225: }
226:
227: private static ClassPool defaultPool = null;
228:
229: /**
230: * Provide a hook so that subclasses can do their own
231: * caching of classes.
232: *
233: * @see #cacheCtClass(String,CtClass,boolean)
234: * @see #removeCached(String)
235: */
236: protected CtClass getCached(String classname) {
237: return (CtClass) classes.get(classname);
238: }
239:
240: /**
241: * Provides a hook so that subclasses can do their own
242: * caching of classes.
243: *
244: * @see #getCached(String)
245: * @see #removeCached(String,CtClass)
246: */
247: protected void cacheCtClass(String classname, CtClass c,
248: boolean dynamic) {
249: classes.put(classname, c);
250: }
251:
252: /**
253: * Provide a hook so that subclasses can do their own
254: * caching of classes.
255: *
256: * @see #getCached(String)
257: * @see #cacheCtClass(String,CtClass,boolean)
258: */
259: protected CtClass removeCached(String classname) {
260: return (CtClass) classes.remove(classname);
261: }
262:
263: /**
264: * Returns the class search path.
265: */
266: public String toString() {
267: return source.toString();
268: }
269:
270: /**
271: * Record a package name so that the Javassist compiler searches
272: * the package to resolve a class name.
273: * Don't record the <code>java.lang</code> package, which has
274: * been implicitly recorded by default.
275: *
276: * <p>Note that <code>get()</code> in <code>ClassPool</code> does
277: * not search the recorded package. Only the compiler searches it.
278: *
279: * @param packageName the package name.
280: * It must not include the last '.' (dot).
281: * For example, "java.util" is valid but "java.util." is wrong.
282: * @since 3.1
283: */
284: public void importPackage(String packageName) {
285: importedPackages.add(packageName);
286: }
287:
288: /**
289: * Clear all the package names recorded by <code>importPackage()</code>.
290: * The <code>java.lang</code> package is not removed.
291: *
292: * @see #importPackage(String)
293: * @since 3.1
294: */
295: public void clearImportedPackages() {
296: importedPackages = new ArrayList();
297: importedPackages.add("java.lang");
298: }
299:
300: /**
301: * Returns all the package names recorded by <code>importPackage()</code>.
302: *
303: * @see #importPackage(String)
304: * @since 3.1
305: */
306: public Iterator getImportedPackages() {
307: return importedPackages.iterator();
308: }
309:
310: /**
311: * Records a name that never exists.
312: * For example, a package name can be recorded by this method.
313: * This would improve execution performance
314: * since <code>get()</code> does not search the class path at all
315: * if the given name is an invalid name recorded by this method.
316: * Note that searching the class path takes relatively long time.
317: *
318: * @param name a class name (separeted by dot).
319: */
320: public void recordInvalidClassName(String name) {
321: source.recordInvalidClassName(name);
322: }
323:
324: /**
325: * Records the <code>$cflow</code> variable for the field specified
326: * by <code>cname</code> and <code>fname</code>.
327: *
328: * @param name variable name
329: * @param cname class name
330: * @param fname field name
331: */
332: void recordCflow(String name, String cname, String fname) {
333: if (cflow == null)
334: cflow = new Hashtable();
335:
336: cflow.put(name, new Object[] { cname, fname });
337: }
338:
339: /**
340: * Undocumented method. Do not use; internal-use only.
341: *
342: * @param name the name of <code>$cflow</code> variable
343: */
344: public Object[] lookupCflow(String name) {
345: if (cflow == null)
346: cflow = new Hashtable();
347:
348: return (Object[]) cflow.get(name);
349: }
350:
351: /**
352: * Reads a class file and constructs a <code>CtClass</code>
353: * object with a new name.
354: * This method is useful if you want to generate a new class as a copy
355: * of another class (except the class name). For example,
356: *
357: * <ul><pre>
358: * getAndRename("Point", "Pair")
359: * </pre></ul>
360: *
361: * returns a <code>CtClass</code> object representing <code>Pair</code>
362: * class. The definition of <code>Pair</code> is the same as that of
363: * <code>Point</code> class except the class name since <code>Pair</code>
364: * is defined by reading <code>Point.class</code>.
365: *
366: * @param orgName the original (fully-qualified) class name
367: * @param newName the new class name
368: */
369: public CtClass getAndRename(String orgName, String newName)
370: throws NotFoundException {
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: */
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: */
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: * @param useCache false if the cached CtClass must be ignored.
431: * @param searchParent false if the parent class pool is not searched.
432: * @return null if the class could not be found.
433: */
434: protected synchronized CtClass get0(String classname,
435: boolean useCache) throws NotFoundException {
436: CtClass clazz = null;
437: if (useCache) {
438: clazz = getCached(classname);
439: if (clazz != null)
440: return clazz;
441: }
442:
443: if (!childFirstLookup && parent != null) {
444: clazz = parent.get0(classname, useCache);
445: if (clazz != null)
446: return clazz;
447: }
448:
449: clazz = createCtClass(classname, useCache);
450: if (clazz != null) {
451: if (useCache)
452: cacheCtClass(classname, clazz, false);
453:
454: return clazz;
455: }
456:
457: if (childFirstLookup && parent != null)
458: clazz = parent.get0(classname, useCache);
459:
460: return clazz;
461: }
462:
463: /**
464: * Creates a CtClass object representing the specified class.
465: * It first examines whether or not the corresponding class
466: * file exists. If yes, it creates a CtClass object.
467: *
468: * @return null if the class file could not be found.
469: */
470: protected CtClass createCtClass(String classname, boolean useCache) {
471: // accept "[L<class name>;" as a class name.
472: if (classname.charAt(0) == '[')
473: classname = Descriptor.toClassName(classname);
474:
475: if (classname.endsWith("[]")) {
476: String base = classname
477: .substring(0, classname.indexOf('['));
478: if ((!useCache || getCached(base) == null)
479: && find(base) == null)
480: return null;
481: else
482: return new CtArray(classname, this );
483: } else if (find(classname) == null)
484: return null;
485: else
486: return new CtClassType(classname, this );
487: }
488:
489: /**
490: * Searches the class path to obtain the URL of the class file
491: * specified by classname. It is also used to determine whether
492: * the class file exists.
493: *
494: * @param classname a fully-qualified class name.
495: * @return null if the class file could not be found.
496: * @see CtClass#getURL()
497: */
498: public URL find(String classname) {
499: return source.find(classname);
500: }
501:
502: /*
503: * Is invoked by CtClassType.setName() and methods in this class.
504: * This method throws an exception if the class is already frozen or
505: * if this class pool cannot edit the class since it is in a parent
506: * class pool.
507: */
508: void checkNotFrozen(String classname) throws RuntimeException {
509: CtClass clazz = getCached(classname);
510: if (clazz == null) {
511: if (!childFirstLookup && parent != null) {
512: try {
513: clazz = parent.get0(classname, true);
514: } catch (NotFoundException e) {
515: }
516: if (clazz != null)
517: throw new RuntimeException(
518: classname
519: + " is in a parent ClassPool. Use the parent.");
520: }
521: } else if (clazz.isFrozen())
522: throw new RuntimeException(classname
523: + ": frozen class (cannot edit)");
524: }
525:
526: /* for CtClassType.getClassFile2(). Don't delegate to the parent.
527: */
528: InputStream openClassfile(String classname)
529: throws NotFoundException {
530: return source.openClassfile(classname);
531: }
532:
533: void writeClassfile(String classname, OutputStream out)
534: throws NotFoundException, IOException,
535: CannotCompileException {
536: source.writeClassfile(classname, out);
537: }
538:
539: /**
540: * Reads class files from the source and returns an array of
541: * <code>CtClass</code>
542: * objects representing those class files.
543: *
544: * <p>If an element of <code>classnames</code> ends with "[]",
545: * then this method
546: * returns a <code>CtClass</code> object for that array type.
547: *
548: * @param classnames an array of fully-qualified class name.
549: */
550: public CtClass[] get(String[] classnames) throws NotFoundException {
551: if (classnames == null)
552: return new CtClass[0];
553:
554: int num = classnames.length;
555: CtClass[] result = new CtClass[num];
556: for (int i = 0; i < num; ++i)
557: result[i] = get(classnames[i]);
558:
559: return result;
560: }
561:
562: /**
563: * Reads a class file and obtains a compile-time method.
564: *
565: * @param classname the class name
566: * @param methodname the method name
567: * @see CtClass#getDeclaredMethod(String)
568: */
569: public CtMethod getMethod(String classname, String methodname)
570: throws NotFoundException {
571: CtClass c = get(classname);
572: return c.getDeclaredMethod(methodname);
573: }
574:
575: /**
576: * Creates a new class (or interface) from the given class file.
577: * If there already exists a class with the same name, the new class
578: * overwrites that previous class.
579: *
580: * <p>This method is used for creating a <code>CtClass</code> object
581: * directly from a class file. The qualified class name is obtained
582: * from the class file; you do not have to explicitly give the name.
583: *
584: * @param classfile class file.
585: * @throws RuntimeException if there is a frozen class with the
586: * the same name.
587: * @see javassist.ByteArrayClassPath
588: */
589: public CtClass makeClass(InputStream classfile) throws IOException,
590: RuntimeException {
591: classfile = new BufferedInputStream(classfile);
592: CtClass clazz = new CtClassType(classfile, this );
593: clazz.checkModify();
594: String classname = clazz.getName();
595: checkNotFrozen(classname);
596: cacheCtClass(classname, clazz, true);
597: return clazz;
598: }
599:
600: /**
601: * Creates a new public class.
602: * If there already exists a class with the same name, the new class
603: * overwrites that previous class.
604: *
605: * @param classname a fully-qualified class name.
606: * @throws RuntimeException if the existing class is frozen.
607: */
608: public CtClass makeClass(String classname) throws RuntimeException {
609: return makeClass(classname, null);
610: }
611:
612: /**
613: * Creates a new public class.
614: * If there already exists a class/interface with the same name,
615: * the new class overwrites that previous class.
616: *
617: * @param classname a fully-qualified class name.
618: * @param superclass the super class.
619: * @throws RuntimeException if the existing class is frozen.
620: */
621: public synchronized CtClass makeClass(String classname,
622: CtClass super class) throws RuntimeException {
623: checkNotFrozen(classname);
624: CtClass clazz = new CtNewClass(classname, this , false,
625: super class);
626: cacheCtClass(classname, clazz, true);
627: return clazz;
628: }
629:
630: /**
631: * Creates a new public nested class.
632: * This method is called by CtClassType.makeNestedClass().
633: *
634: * @param classname a fully-qualified class name.
635: * @return the nested class.
636: */
637: synchronized CtClass makeNestedClass(String classname) {
638: checkNotFrozen(classname);
639: CtClass clazz = new CtNewNestedClass(classname, this , false,
640: null);
641: cacheCtClass(classname, clazz, true);
642: return clazz;
643: }
644:
645: /**
646: * Creates a new public interface.
647: * If there already exists a class/interface with the same name,
648: * the new interface overwrites that previous one.
649: *
650: * @param name a fully-qualified interface name.
651: * @throws RuntimeException if the existing interface is frozen.
652: */
653: public CtClass makeInterface(String name) throws RuntimeException {
654: return makeInterface(name, null);
655: }
656:
657: /**
658: * Creates a new public interface.
659: * If there already exists a class/interface with the same name,
660: * the new interface overwrites that previous one.
661: *
662: * @param name a fully-qualified interface name.
663: * @param superclass the super interface.
664: * @throws RuntimeException if the existing interface is frozen.
665: */
666: public synchronized CtClass makeInterface(String name,
667: CtClass super class) throws RuntimeException {
668: checkNotFrozen(name);
669: CtClass clazz = new CtNewClass(name, this , true, super class);
670: cacheCtClass(name, clazz, true);
671: return clazz;
672: }
673:
674: /**
675: * Appends the system search path to the end of the
676: * search path. The system search path
677: * usually includes the platform library, extension
678: * libraries, and the search path specified by the
679: * <code>-classpath</code> option or the <code>CLASSPATH</code>
680: * environment variable.
681: *
682: * @return the appended class path.
683: */
684: public ClassPath appendSystemPath() {
685: return source.appendSystemPath();
686: }
687:
688: /**
689: * Insert a <code>ClassPath</code> object at the head of the
690: * search path.
691: *
692: * @return the inserted class path.
693: * @see javassist.ClassPath
694: * @see javassist.URLClassPath
695: * @see javassist.ByteArrayClassPath
696: */
697: public ClassPath insertClassPath(ClassPath cp) {
698: return source.insertClassPath(cp);
699: }
700:
701: /**
702: * Appends a <code>ClassPath</code> object to the end of the
703: * search path.
704: *
705: * @return the appended class path.
706: * @see javassist.ClassPath
707: * @see javassist.URLClassPath
708: * @see javassist.ByteArrayClassPath
709: */
710: public ClassPath appendClassPath(ClassPath cp) {
711: return source.appendClassPath(cp);
712: }
713:
714: /**
715: * Inserts a directory or a jar (or zip) file at the head of the
716: * search path.
717: *
718: * @param pathname the path name of the directory or jar file.
719: * It must not end with a path separator ("/").
720: * @return the inserted class path.
721: * @throws NotFoundException if the jar file is not found.
722: */
723: public ClassPath insertClassPath(String pathname)
724: throws NotFoundException {
725: return source.insertClassPath(pathname);
726: }
727:
728: /**
729: * Appends a directory or a jar (or zip) file to the end of the
730: * search path.
731: *
732: * @param pathname the path name of the directory or jar file.
733: * It must not end with a path separator ("/").
734: * @return the appended class path.
735: * @throws NotFoundException if the jar file is not found.
736: */
737: public ClassPath appendClassPath(String pathname)
738: throws NotFoundException {
739: return source.appendClassPath(pathname);
740: }
741:
742: /**
743: * Detatches the <code>ClassPath</code> object from the search path.
744: * The detached <code>ClassPath</code> object cannot be added
745: * to the pathagain.
746: */
747: public void removeClassPath(ClassPath cp) {
748: source.removeClassPath(cp);
749: }
750:
751: /**
752: * Appends directories and jar files for search.
753: *
754: * <p>The elements of the given path list must be separated by colons
755: * in Unix or semi-colons in Windows.
756: *
757: * @param pathlist a (semi)colon-separated list of
758: * the path names of directories and jar files.
759: * The directory name must not end with a path
760: * separator ("/").
761: * @throws NotFoundException if a jar file is not found.
762: */
763: public void appendPathList(String pathlist)
764: throws NotFoundException {
765: char sep = File.pathSeparatorChar;
766: int i = 0;
767: for (;;) {
768: int j = pathlist.indexOf(sep, i);
769: if (j < 0) {
770: appendClassPath(pathlist.substring(i));
771: break;
772: } else {
773: appendClassPath(pathlist.substring(i, j));
774: i = j + 1;
775: }
776: }
777: }
778:
779: /**
780: * Converts the given class to a <code>java.lang.Class</code> object.
781: * Once this method is called, further modifications are not
782: * allowed any more.
783: * To load the class, this method uses the context class loader
784: * of the current thread. It is obtained by calling
785: * <code>getClassLoader()</code>.
786: *
787: * <p>This behavior can be changed by subclassing the pool and changing
788: * the <code>getClassLoader()</code> method.
789: * If the program is running on some application
790: * server, the context class loader might be inappropriate to load the
791: * class.
792: *
793: * <p>This method is provided for convenience. If you need more
794: * complex functionality, you should write your own class loader.
795: *
796: * <p><b>Warining:</b> A Class object returned by this method may not
797: * work with a security manager or a signed jar file because a
798: * protection domain is not specified.
799: *
800: * @see #toClass(CtClass, java.lang.ClassLoader, ProtectionDomain)
801: * @see #getClassLoader()
802: */
803: public Class toClass(CtClass clazz) throws CannotCompileException {
804: // Some subclasses of ClassPool may override toClass(CtClass,ClassLoader).
805: // So we should call that method instead of toClass(.., ProtectionDomain).
806: return toClass(clazz, getClassLoader());
807: }
808:
809: /**
810: * Get the classloader for <code>toClass()</code>, <code>getAnnotations()</code> in
811: * <code>CtClass</code>, etc.
812: *
813: * <p>The default is the context class loader.
814: *
815: * @return the classloader for the pool
816: * @see #toClass(CtClass)
817: * @see CtClass#getAnnotations()
818: */
819: public ClassLoader getClassLoader() {
820: return getContextClassLoader();
821: }
822:
823: /**
824: * Obtains a class loader that seems appropriate to look up a class
825: * by name.
826: */
827: static ClassLoader getContextClassLoader() {
828: return Thread.currentThread().getContextClassLoader();
829: }
830:
831: /**
832: * Converts the class to a <code>java.lang.Class</code> object.
833: * Do not override this method any more at a subclass because
834: * <code>toClass(CtClass)</code> never calls this method.
835: *
836: * <p><b>Warining:</b> A Class object returned by this method may not
837: * work with a security manager or a signed jar file because a
838: * protection domain is not specified.
839: *
840: * @deprecated Replaced by {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
841: * A subclass of <code>ClassPool</code> that has been
842: * overriding this method should be modified. It should override
843: * {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
844: */
845: public Class toClass(CtClass ct, ClassLoader loader)
846: throws CannotCompileException {
847: return toClass(ct, loader, null);
848: }
849:
850: /**
851: * Converts the class to a <code>java.lang.Class</code> object.
852: * Once this method is called, further modifications are not allowed
853: * any more.
854: *
855: * <p>The class file represented by the given <code>CtClass</code> is
856: * loaded by the given class loader to construct a
857: * <code>java.lang.Class</code> object. Since a private method
858: * on the class loader is invoked through the reflection API,
859: * the caller must have permissions to do that.
860: *
861: * <p>An easy way to obtain <code>ProtectionDomain</code> object is
862: * to call <code>getProtectionDomain()</code>
863: * in <code>java.lang.Class</code>. It returns the domain that the
864: * class belongs to.
865: *
866: * <p>This method is provided for convenience. If you need more
867: * complex functionality, you should write your own class loader.
868: *
869: * @param loader the class loader used to load this class.
870: * For example, the loader returned by
871: * <code>getClassLoader()</code> can be used
872: * for this parameter.
873: * @param domain the protection domain for the class.
874: * If it is null, the default domain created
875: * by <code>java.lang.ClassLoader</code> is used.
876: *
877: * @see #getClassLoader()
878: * @since 3.3
879: */
880: public Class toClass(CtClass ct, ClassLoader loader,
881: ProtectionDomain domain) throws CannotCompileException {
882: try {
883: byte[] b = ct.toBytecode();
884: java.lang.reflect.Method method;
885: Object[] args;
886: if (domain == null) {
887: method = defineClass1;
888: args = new Object[] { ct.getName(), b, new Integer(0),
889: new Integer(b.length) };
890: } else {
891: method = defineClass2;
892: args = new Object[] { ct.getName(), b, new Integer(0),
893: new Integer(b.length), domain };
894: }
895:
896: return toClass2(method, loader, args);
897: } catch (RuntimeException e) {
898: throw e;
899: } catch (java.lang.reflect.InvocationTargetException e) {
900: throw new CannotCompileException(e.getTargetException());
901: } catch (Exception e) {
902: throw new CannotCompileException(e);
903: }
904: }
905:
906: private static synchronized Class toClass2(Method method,
907: ClassLoader loader, Object[] args) throws Exception {
908: method.setAccessible(true);
909: Class clazz = (Class) method.invoke(loader, args);
910: method.setAccessible(false);
911: return clazz;
912: }
913: }
|