You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Loader.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 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. package javassist;
  16. import java.io.*;
  17. import java.util.Hashtable;
  18. import java.util.Vector;
  19. /**
  20. * The class loader for Javassist (JDK 1.2 or later only).
  21. *
  22. * <p>This is a sample class loader using <code>ClassPool</code>.
  23. * Unlike a regular class loader, this class loader obtains bytecode
  24. * from a <code>ClassPool</code>.
  25. *
  26. * <p>Note that Javassist can be used without this class loader; programmers
  27. * can define their own versions of class loader. They can run
  28. * a program even without any user-defined class loader if that program
  29. * is statically translated with Javassist.
  30. * This class loader is just provided as a utility class.
  31. *
  32. * <p>Suppose that an instance of <code>MyTranslator</code> implementing
  33. * the interface <code>Translator</code> is responsible for modifying
  34. * class files.
  35. * The startup program of an application using <code>MyTranslator</code>
  36. * should be something like this:
  37. *
  38. * <ul><pre>
  39. * import javassist.*;
  40. *
  41. * public class Main {
  42. * public static void main(String[] args) throws Throwable {
  43. * MyTranslator myTrans = new MyTranslator();
  44. * ClassPool cp = ClassPool.getDefault(myTrans);
  45. * Loader cl = new Loader(cp);
  46. * cl.run("MyApp", args);
  47. * }
  48. * }
  49. * </pre></ul>
  50. *
  51. * <p>Class <code>MyApp</code> is the main program of the application.
  52. *
  53. * <p>This program should be executed as follows:
  54. *
  55. * <ul><pre>
  56. * % java Main <i>arg1</i> <i>arg2</i>...
  57. * </pre></ul>
  58. *
  59. * <p>It modifies the class <code>MyApp</code> with a <code>MyTranslator</code>
  60. * object before loading it into the JVM.
  61. * Then it calls <code>main()</code> in <code>MyApp</code> with arguments
  62. * <i>arg1</i>, <i>arg2</i>, ...
  63. *
  64. * <p>This program execution is equivalent to:
  65. *
  66. * <ul><pre>
  67. * % java MyApp <i>arg1</i> <i>arg2</i>...
  68. * </pre></ul>
  69. *
  70. * <p>except that classes are translated by <code>MyTranslator</code>
  71. * at load time.
  72. *
  73. * <p>If only a particular class is modified when it is loaded,
  74. * a program like the following can be used:
  75. *
  76. * <ul><pre>ClassPool cp = ClassPool.getDefault();
  77. * Loader cl = new Loader(cp);
  78. *
  79. * CtClass ct = cp.get("test.Rectangle");
  80. * ct.setSuperclass(loader.get("test.Point"));
  81. *
  82. * Class c = cl.loadClass("test.Rectangle");
  83. * Object rect = c.newInstance();</pre></ul>
  84. *
  85. * <p>This program modifies the super class of the <code>Rectangle</code>
  86. * class and loads it into the JVM with a class loader <code>cl</code>.
  87. *
  88. * <p><b>Note 1:</b>
  89. *
  90. * <p>This class loader does not allow the users to intercept the loading
  91. * of <code>java.*</code> and <code>javax.*</code> classes unless
  92. * <code>Loader.doDelegation</code> is <code>false</code>. Also see
  93. * Note 2.
  94. *
  95. * <p><b>Note 2:</b>
  96. *
  97. * <p>If classes are loaded with different class loaders, they belong to
  98. * separate name spaces. If class <code>C</code> is loaded by a class
  99. * loader <code>CL</code>, all classes that the class <code>C</code>
  100. * refers to are also loaded by <code>CL</code>. However, if <code>CL</code>
  101. * delegates the loading of the class <code>C</code> to <code>CL'</code>,
  102. * then those classes that the class <code>C</code> refers to
  103. * are loaded by a parent class loader <code>CL'</code>
  104. * instead of <code>CL</code>.
  105. *
  106. * <p>If an object of class <code>C</code> is assigned
  107. * to a variable of class <code>C</code> belonging to a different name
  108. * space, then a <code>ClassCastException</code> is thrown.
  109. *
  110. * <p>Because of the fact above, this loader delegates only the loading of
  111. * <code>javassist.Loader</code>
  112. * and classes included in package <code>java.*</code> and
  113. * <code>javax.*</code> to the parent class
  114. * loader. Other classes are directly loaded by this loader.
  115. *
  116. * <p>For example, suppose that <code>java.lang.String</code> would be loaded
  117. * by this loader while <code>java.io.File</code> is loaded by the parent
  118. * class loader. If the constructor of <code>java.io.File</code> is called
  119. * with an instance of <code>java.lang.String</code>, then it may throw
  120. * an exception since it accepts an instance of only the
  121. * <code>java.lang.String</code> loaded by the parent class loader.
  122. *
  123. * @see javassist.ClassPool
  124. * @see javassist.Translator
  125. */
  126. public class Loader extends ClassLoader {
  127. private Hashtable notDefinedHere; // must be atomic.
  128. private Vector notDefinedPackages; // must be atomic.
  129. private ClassPool source;
  130. /**
  131. * Specifies the algorithm of class loading.
  132. *
  133. * <p>This class loader uses the parent class loader for
  134. * <code>java.*</code> and <code>javax.*</code> classes.
  135. * If this variable <code>doDelegation</code>
  136. * is <code>false</code>, this class loader does not delegate those
  137. * classes to the parent class loader.
  138. *
  139. * <p>The default value is <code>true</code>.
  140. */
  141. public boolean doDelegation = true;
  142. /**
  143. * Creates a new class loader.
  144. */
  145. public Loader() {
  146. this(null);
  147. }
  148. /**
  149. * Creates a new class loader.
  150. *
  151. * @param cp the source of class files.
  152. */
  153. public Loader(ClassPool cp) {
  154. init(cp);
  155. }
  156. /**
  157. * Creates a new class loader
  158. * using the specified parent class loader for delegation.
  159. *
  160. * @param parent the parent class loader.
  161. * @param cp the source of class files.
  162. */
  163. public Loader(ClassLoader parent, ClassPool cp) {
  164. super(parent);
  165. init(cp);
  166. }
  167. private void init(ClassPool cp) {
  168. notDefinedHere = new Hashtable();
  169. notDefinedPackages = new Vector();
  170. source = cp;
  171. delegateLoadingOf("javassist.Loader");
  172. }
  173. /**
  174. * Records a class so that the loading of that class is delegated
  175. * to the parent class loader.
  176. *
  177. * <p>If the given class name ends with <code>.</code> (dot), then
  178. * that name is interpreted as a package name. All the classes
  179. * in that package and the sub packages are delegated.
  180. */
  181. public void delegateLoadingOf(String classname) {
  182. if (classname.endsWith("."))
  183. notDefinedPackages.addElement(classname);
  184. else
  185. notDefinedHere.put(classname, this);
  186. }
  187. /**
  188. * Sets the soruce <code>ClassPool</code>.
  189. */
  190. public void setClassPool(ClassPool cp) {
  191. source = cp;
  192. }
  193. /**
  194. * Loads a class with an instance of <code>Loader</code>
  195. * and calls <code>main()</code> of that class.
  196. *
  197. * <p>This method calls <code>run()</code>.
  198. *
  199. * @param args[0] class name to be loaded.
  200. * @param args[1-n] parameters passed to <code>main()</code>.
  201. *
  202. * @see javassist.Loader#run(String[])
  203. */
  204. public static void main(String[] args) throws Throwable {
  205. Loader cl = new Loader();
  206. cl.run(args);
  207. }
  208. /**
  209. * Loads a class and calls <code>main()</code> in that class.
  210. *
  211. * @param args[0] the name of the loaded class.
  212. * @param args[1-n] parameters passed to <code>main()</code>.
  213. */
  214. public void run(String[] args) throws Throwable {
  215. int n = args.length - 1;
  216. if (n >= 0) {
  217. String[] args2 = new String[n];
  218. for (int i = 0; i < n; ++i)
  219. args2[i] = args[i + 1];
  220. run(args[0], args2);
  221. }
  222. }
  223. /**
  224. * Loads a class and calls <code>main()</code> in that class.
  225. *
  226. * @param classname the loaded class.
  227. * @param args parameters passed to <code>main()</code>.
  228. */
  229. public void run(String classname, String[] args) throws Throwable {
  230. Class c = loadClass(classname);
  231. try {
  232. c.getDeclaredMethod("main", new Class[] { String[].class })
  233. .invoke(null, new Object[] { args });
  234. }
  235. catch (java.lang.reflect.InvocationTargetException e) {
  236. throw e.getTargetException();
  237. }
  238. }
  239. /**
  240. * Requests the class loader to load a class.
  241. */
  242. protected Class loadClass(String name, boolean resolve)
  243. throws ClassFormatError, ClassNotFoundException
  244. {
  245. Class c = findLoadedClass(name);
  246. if (c == null)
  247. c = loadClassByDelegation(name);
  248. if (c == null)
  249. c = findClass(name);
  250. if (c == null)
  251. c = delegateToParent(name);
  252. if (resolve)
  253. resolveClass(c);
  254. return c;
  255. }
  256. /**
  257. * Finds the specified class using <code>ClassPath</code>.
  258. * If the source throws an exception, this returns null.
  259. *
  260. * <p>This method can be overridden by a subclass of
  261. * <code>Loader</code>.
  262. */
  263. protected Class findClass(String name) {
  264. byte[] classfile;
  265. try {
  266. if (source != null)
  267. classfile = source.write(name);
  268. else {
  269. String jarname = "/" + name.replace('.', '/') + ".class";
  270. InputStream in = this.getClass().getResourceAsStream(jarname);
  271. classfile = ClassPoolTail.readStream(in);
  272. }
  273. }
  274. catch (Exception e) {
  275. return null;
  276. }
  277. return defineClass(name, classfile, 0, classfile.length);
  278. }
  279. private Class loadClassByDelegation(String name)
  280. throws ClassNotFoundException
  281. {
  282. /* The swing components must be loaded by a system
  283. * class loader.
  284. * javax.swing.UIManager loads a (concrete) subclass
  285. * of LookAndFeel by a system class loader and cast
  286. * an instance of the class to LookAndFeel for
  287. * (maybe) a security reason. To avoid failure of
  288. * type conversion, LookAndFeel must not be loaded
  289. * by this class loader.
  290. */
  291. Class c = null;
  292. if (doDelegation)
  293. if (name.startsWith("java.") || name.startsWith("javax.")
  294. || name.startsWith("sun.") || name.startsWith("com.sun.")
  295. || notDelegated(name))
  296. c = delegateToParent(name);
  297. return c;
  298. }
  299. private boolean notDelegated(String name) {
  300. if (notDefinedHere.get(name) != null)
  301. return true;
  302. int n = notDefinedPackages.size();
  303. for (int i = 0; i < n; ++i)
  304. if (name.startsWith((String)notDefinedPackages.elementAt(i)))
  305. return true;
  306. return false;
  307. }
  308. private Class delegateToParent(String classname)
  309. throws ClassNotFoundException
  310. {
  311. ClassLoader cl = getParent();
  312. if (cl != null)
  313. return cl.loadClass(classname);
  314. else
  315. return findSystemClass(classname);
  316. }
  317. }