Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

tutorial.html 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  4. <title>Javassist Tutorial</title>
  5. <link rel="stylesheet" type="text/css" href="brown.css">
  6. </head>
  7. <body>
  8. <b>
  9. <font size="+3">
  10. Getting Started with Javassist
  11. </font>
  12. <p><font size="+2">
  13. Shigeru Chiba
  14. </font>
  15. </b>
  16. <p><div align="right"><a href="tutorial2.html">Next page</a></div>
  17. <ul>1. <a href="#read">Reading bytecode</a>
  18. <br>2. <a href="#def">Defining a new class</a>
  19. <br>3. <a href="#pool">ClassPool</a>
  20. <br>4. <a href="#load">Class loader</a>
  21. <br>5. <a href="tutorial2.html#intro">Introspection and customization</a>
  22. </ul>
  23. <p><br>
  24. <a name="read">
  25. <h2>1. Reading bytecode</h2>
  26. <p>Javassist is a class library for dealing with Java bytecode.
  27. Java bytecode is stored in a binary file called a class file.
  28. Each class file contains one Java class or interface.
  29. <p>The class <code>Javassist.CtClass</code> is an abstract
  30. representation of a class file. A <code>CtClass</code> (compile-time
  31. class) object is a handle for dealing with a class file. The
  32. following program is a very simple example:
  33. <ul><pre>
  34. ClassPool pool = ClassPool.getDefault();
  35. CtClass cc = pool.get("test.Rectangle");
  36. cc.setSuperclass(pool.get("test.Point"));
  37. cc.writeFile("test.Rectangle");
  38. </pre></ul>
  39. <p>This program first obtains a <code>ClassPool</code> object,
  40. which controls bytecode modification with Javassist.
  41. The <code>ClassPool</code> object is a container of <code>CtClass</code>
  42. object representing a class file.
  43. It reads a class file on demand for constructing a <code>CtClass</code>
  44. object and contains the constructed object until it is written out
  45. to a file or an output stream.
  46. <p>The <code>ClassPool</code> object is used to maintain one-to-one
  47. mapping between classes and <code>CtClass</code> objects. Javassist
  48. never allows two distinct <code>CtClass</code> objects to represent
  49. the same class unless two independent <code>ClassPool</code> are created.
  50. This is a significant feature for consistent program
  51. transformaiton. To create multiple
  52. instances of <code>ClassPool</code>, write the following code:
  53. <ul><pre>
  54. ClassPool cp = new ClassPool();
  55. cp.appendSystemPath(); // or append another path by appendClassPath()
  56. </pre></ul>
  57. <p>This creates a <code>ClassPool</code> object that behaves as the
  58. default <code>ClassPool</code> returned by
  59. <code>ClassPool.getDefault()</code> does.
  60. <code>ClassPool.getDefault()</code> is a singleton factory method
  61. provided for convenience.
  62. <p>If you have two <code>ClassPool</code> objects, then you can
  63. obtain, from each <code>ClassPool</code>, a distinct
  64. <code>CtClass</code> object representing the same class file. You can
  65. differently modify these <code>CtClass</code> objects to generate
  66. different versions of the class.
  67. <p>To modify the definition of a class, the users must first obtain a
  68. reference to the <code>CtClass</code> object representing that class.
  69. <code>get()</code> in <code>ClassPool</code> is used for this purpose.
  70. In the case of the program shown at the beginning, the
  71. <code>CtClass</code> object representing a class
  72. <code>test.Rectangle</code> is obtained from the
  73. <code>ClassPool</code> object and it is assigned to a variable
  74. <code>cc</code>. Then it is modified so that the superclass of
  75. <code>test.Rectangle</code> is changed into a class
  76. <code>test.Point</code>. This change is reflected on the original
  77. class file when <code>writeFile()</code> in <code>CtClass()</code> is
  78. finally called.
  79. <p><code>writeFile()</code> translates the <code>CtClass</code> object
  80. into a class file and writes it on a local disk.
  81. Javassist also provides a method for directly obtaining the
  82. modified bytecode. To obtain the bytecode, call <code>toBytecode()</code>:
  83. <ul><pre>
  84. byte[] b = cc.toBytecode();
  85. </pre></ul>
  86. <p>The default <code>ClassPool</code> returned
  87. by a static method <code>ClassPool.getDefault()</code>
  88. searches the same path that the underlying JVM (Java virtual machine) has.
  89. The users can expand this class search path if needed.
  90. For example, the following code adds a directory
  91. <code>/usr/local/javalib</code>
  92. to the search path:
  93. <ul><pre>
  94. ClassPool pool = ClassPool.getDefault();
  95. pool.insertClassPath("/usr/local/javalib");
  96. </pre></ul>
  97. <p>The search path that the users can add is not only a directory but also
  98. a URL:
  99. <ul><pre>
  100. ClassPool pool = ClassPool.getDefault();
  101. ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
  102. pool.insertClassPath(cp);
  103. </pre></ul>
  104. <p>This program adds "http://www.javassist.org:80/java/" to the class search
  105. path. This URL is used only for searching classes belonging to a
  106. package <code>org.javassist</code>.
  107. <p>Furthermore, you can directly give a byte array
  108. to a <code>ClassPool</code> object
  109. and construct a <code>CtClass</code> object from that array. To do this,
  110. use <code>ByteArrayClassPath</code>. For example,
  111. <ul><pre>
  112. ClassPool cp = ClassPool.getDefault();
  113. byte[] b = <em>a byte array</em>;
  114. String name = <em>class name</em>;
  115. cp.insertClassPath(new ByteArrayClassPath(name, b));
  116. CtClass cc = cp.get(name);
  117. </pre></ul>
  118. <p>The obtained <code>CtClass</code> object represents
  119. a class defined by the class file specified by <code>b</code>.
  120. The <code>ClassPool</code> reads a class file from the given
  121. <code>ByteArrayClassPath</code> if <code>get()</code> is called
  122. and the class name given to <code>get()</code> is equal to
  123. one specified by <code>name</code>.
  124. <p>If you do not know the fully-qualified name of the class, then you
  125. can use <code>makeClass()</code> in <code>ClassPool</code>:
  126. <ul><pre>
  127. ClassPool cp = ClassPool.getDefault();
  128. InputStream ins = <em>an input stream for reading a class file</em>;
  129. CtClass cc = cp.makeClass(ins);
  130. </pre></ul>
  131. <p><code>makeClass()</code> returns the <code>CtClass</code> object
  132. constructed from the given input stream. You can use
  133. <code>makeClass()</code> for eagerly feeding class files to
  134. the <code>ClassPool</code> object. This might improve performance
  135. if the search path includes a large jar file. Since
  136. a <code>ClassPool</code> object reads a class file on demand,
  137. it might repeatedly search the whole jar file for every class file.
  138. <code>makeClass()</code> can be used for optimizing this search.
  139. The <code>CtClass</code> constructed by <code>makeClass()</code>
  140. is kept in the <code>ClassPool</code> object and the class file is never
  141. read again.
  142. <p>The users can extend the class search path. They can define a new
  143. class implementing <code>ClassPath</code> interface and give an
  144. instance of that class to <code>insertClassPath()</code> in
  145. <code>ClassPool</code>. This allows a non-standard resource to be
  146. included in the search path.
  147. <p><br>
  148. <a name="def">
  149. <h2>2. Defining a new class</h2>
  150. <p>To define a new class from scratch, <code>makeClass()</code>
  151. must be called on a <code>ClassPool</code>.
  152. <ul><pre>
  153. ClassPool pool = ClassPool.getDefault();
  154. CtClass cc = pool.makeClass("Point");
  155. </pre></ul>
  156. <p>This program defines a class <code>Point</code>
  157. including no members.
  158. <p>A new class can be also defined as a copy of an existing class.
  159. The program below does that:
  160. <ul><pre>
  161. ClassPool pool = ClassPool.getDefault();
  162. CtClass cc = pool.get("Point");
  163. cc.setName("Pair");
  164. </pre></ul>
  165. <p>This program first obtains the <code>CtClass</code> object
  166. for class <code>Point</code>. Then it gives a new name <code>Pair</code>
  167. to that <code>CtClass</code> object.
  168. If <code>get("Point")</code> is later called on the <code>ClassPool</code>
  169. object again, then a class file <code>Point.class</code> is read again and
  170. a new <code>CtClass</code> object for class <code>Point</code> is constructed
  171. again. See the followings:
  172. <ul><pre>
  173. ClassPool pool = ClassPool.getDefault();
  174. CtClass cc = pool.get("Point");
  175. CtClass cc1 = pool.get("Point"); // cc1 is identical to cc.
  176. cc.setName("Pair");
  177. CtClass cc2 = pool.get("Pair"); // cc2 is identical to cc.
  178. CtClass cc3 = pool.get("Point"); // cc3 is not identical to cc.
  179. </pre></ul>
  180. <p>Once a <code>CtClass</code> object is converted into a class file
  181. by <code>writeFile()</code> or <code>toBytecode()</code>, Javassist
  182. rejects further modifications of that <code>CtClass</code> object.
  183. Hence, after the <code>CtClass</code> object representing <code>Point</code>
  184. class is converted into a class file, you cannot define <code>Pair</code>
  185. class as a copy of <code>Point</code> since executing <code>setName()</code>
  186. on <code>Point</code> is rejected.
  187. <p>To avoid this restriction, you should call <code>getAndRename()</code>
  188. in <code>ClassPool</code>. For example,
  189. <ul><pre>
  190. ClassPool pool = ClassPool.getDefault();
  191. CtClass cc = pool.getAndRename("Point", "Pair");
  192. </pre></ul>
  193. <p>If <code>getAndRename()</code> is called, the <code>ClassPool</code>
  194. reads <code>Point.class</code> for creating a new <code>CtClass</code>
  195. object representing <code>Pair</code> class. <code>getAndRename()</code>
  196. can be executed after <code>writeFile()</code> or <code>toBytecode()</code>
  197. is called on the the <code>ClassPool</code> representing <code>Point</code>
  198. class.
  199. <p><br>
  200. <a name="pool">
  201. <h2>3. ClassPool</h2>
  202. <p>
  203. A <code>ClassPool</code> object is a container of <code>CtClass</code>
  204. objects. Once a <code>CtClass</code> object is created, it is
  205. recorded in a <code>ClassPool</code> for ever. This is because a
  206. compiler may need to access the <code>CtClass</code> object later when
  207. it compiles source code that refers to the class represented by that
  208. <code>CtClass</code>. If the class definition represented by that
  209. <code>CtClass</code> object is different from that of the original class
  210. file, the compiler cannot correctly compile the source code without
  211. the <code>CtClass</code> object.
  212. <p>
  213. This specification of <code>ClassPool</code> may cause huge memory
  214. consumption if the number of <code>CtClass</code> objects becomes large.
  215. To avoid this problem, you can explicitly remove an unnecessary
  216. <code>CtClass</code> object from the <code>ClassPool</code>. If you
  217. call <code>detach()</code> on a <code>CtClass</code> object, then that
  218. <code>CtClass</code> object is removed from the <code>ClassPool</code>.
  219. For example,
  220. <ul><pre>
  221. CtClass cc = ... ;
  222. cc.writeFile();
  223. cc.detach();
  224. </pre></ul>
  225. <p>You must not call any method on that
  226. <code>CtClass</code> object after <code>detach()</code> is called.
  227. <p><code>ClassPool</code> objects can be cascaded like
  228. <code>java.lang.ClassLoader</code>. For example,
  229. <ul><pre>
  230. ClassPool parent = ClassPool.getDefault();
  231. ClassPool child = new ClassPool(parent);
  232. </pre></ul>
  233. <p>If <code>child.get()</code> is called, the child <code>ClassPool</code>
  234. first delegates to the parent <code>ClassPool</code>. If the parent
  235. <code>ClassPool</code> fails to find a class file, then the child
  236. <code>ClassPool</code> attempts to find a class file.
  237. If <code>child.childFirstLookup</code> is true, the child
  238. <code>ClassPool</code> attempts to find a class file before delegating
  239. to the parent <code>ClassPool</code>. For example,
  240. <ul><pre>
  241. ClassPool parent = ClassPool.getDefault();
  242. ClassPool child = new ClassPool(parent);
  243. child.childFirstLookup = true; // changes the behavior of the child.
  244. </pre></ul>
  245. <p><br>
  246. <a name="load">
  247. <h2>4. Class loader</h2>
  248. <p>If what classes must be modified is known in advance,
  249. the easiest way for modifying the classes is as follows:
  250. <ul><li>1. Get a <code>CtClass</code> object by calling
  251. <code>ClassPool.get()</code>,
  252. <li>2. Modify it, and
  253. <li>3. Call <code>writeFile()</code> or <code>toBytecode()</code>
  254. on that <code>CtClass</code> object.
  255. </ul>
  256. <p>If whether a class is modified or not is determined at load time,
  257. the users must make Javassist collaborate with a class loader.
  258. Javassist can be used with a class loader so that bytecode can be
  259. modified at load time. The users of Javassist can define their own
  260. version of class loader but they can also use a class loader provided
  261. by Javassist.
  262. <p>Using a class loader is not easy. In particular, if you are a
  263. beginner, you should separate your program into an application program
  264. and an instrumentation program. Then you should load only the former
  265. program by a user-defined class loader. The latter one, as well as
  266. the program of the user-defined class loader, should be loaded by the
  267. system class loader.
  268. <p><br>
  269. <h3>4.1 Class loading in Java</h3>
  270. <p>In Java, multiple class loaders can coexist and
  271. each class loader creates its own name space.
  272. Different class loaders can load different class files with the
  273. same class name. The loaded two classes are regarded as different
  274. ones. This feature enables us to run multiple application programs
  275. on a single JVM.
  276. <p>If the same class file is loaded by two distinct class loaders,
  277. the JVM makes two distinct classes with the same name and definition.
  278. The two classes are regarded as different ones.
  279. Since the two classes are not identical, an instance of one class is
  280. not assignable to a variable of the other class. The cast operation
  281. between the two classes fails and throws a <code>ClassCastException</code>.
  282. <p>Multiple class loaders form a tree structure.
  283. Each class loader except the bootstrap loader has a
  284. parent class loader, which has normally loaded the class of that child
  285. class loader. Since the request to load a class can be delegated along this
  286. hierarchy of class loaders, a class may be loaded by a class loader that
  287. you do not request the class loading.
  288. Therefore, the class loader that has been requested to load a class C
  289. may be different from the loader that actually loads the class C.
  290. For distinction, we call the former loader <em>the initiator of C</em>
  291. and we call the latter loader <em>the real loader of C</em>.
  292. <p>
  293. Furthermore, if a class loader CL requested to load a class C
  294. (the initiator of C) delegates
  295. to the parent class loader PL, then the class loader CL is never requested
  296. to load any classes referred to in the definition of the class C.
  297. CL is not the initiator of those classes.
  298. Instead, the parent class loader PL becomes their initiators
  299. and it is requested to load them.
  300. <em>The classes that the definition of a class C referes to are loaded by
  301. the real loader of C.</em>
  302. <p>To understand this behavior, let's consider the following example.
  303. <ul><pre>
  304. public class Point { // loaded by PL
  305. private int x, y;
  306. public int getX() { return x; }
  307. :
  308. }
  309. public class Box { // the initiator is L but the real loader is PL
  310. private Point upperLeft, size;
  311. public int getBaseX() { return upperLeft.x; }
  312. :
  313. }
  314. public class Window { // loaded by a class loader L
  315. private Box box;
  316. public int getBaseX() { return box.getBaseX(); }
  317. }</pre></ul>
  318. <p>Suppose that a class <code>Window</code> is loaded by a class loader L.
  319. Both the initiator and the real loader of <code>Window</code> are L.
  320. Since the definition of <code>Window</code> refers to <code>Box</code>,
  321. the JVM will request L to load <code>Box</code>.
  322. Here, suppose that L delegates this task to the parent class loader PL.
  323. The initiator of <code>Box</code> is L but the real loader is PL.
  324. In this case, the initiator of <code>Point</code> is not L but PL
  325. since it is the same as the real loader of <code>Box</code>.
  326. Thus L is never requested to load <code>Point</code>.
  327. <p>Next, let's consider a slightly modified example.
  328. <ul><pre>
  329. public class Point {
  330. private int x, y;
  331. public int getX() { return x; }
  332. :
  333. }
  334. public class Box { // the initiator is L but the real loader is PL
  335. private Point upperLeft, size;
  336. public Point getSize() { return size; }
  337. :
  338. }
  339. public class Window { // loaded by a class loader L
  340. private Box box;
  341. public boolean widthIs(int w) {
  342. Point p = box.getSize();
  343. return w == p.getX();
  344. }
  345. }</pre></ul>
  346. <p>Now, the definition of <code>Window</code> also refers to
  347. <code>Point</code>. In this case, the class loader L must
  348. also delegate to PL if it is requested to load <code>Point</code>.
  349. <em>You must avoid having two class loaders doubly load the same
  350. class.</em> One of the two loaders must delegate to
  351. the other.
  352. <p>
  353. If L does not delegate to PL when <code>Point</code>
  354. is loaded, <code>widthIs()</code> would throw a ClassCastException.
  355. Since the real loader of <code>Box</code> is PL,
  356. <code>Point</code> referred to in <code>Box</code> is also loaded by PL.
  357. Therefore, the resulting value of <code>getSize()</code>
  358. is an instance of <code>Point</code> loaded by PL
  359. whereas the type of the variable <code>p</code> in <code>widthIs()</code>
  360. is <code>Point</code> loaded by L.
  361. The JVM regards them as distinct types and thus it throws an exception
  362. because of type mismatch.
  363. <p>This behavior is somewhat inconvenient but necessary.
  364. If the following statement:
  365. <ul><pre>
  366. Point p = box.getSize();
  367. </pre></ul>
  368. <p>did not throw an exception,
  369. then the programmer of <code>Window</code> could break the encapsulation
  370. of <code>Point</code> objects.
  371. For example, the field <code>x</code>
  372. is private in <code>Point</code> loaded by PL.
  373. However, the <code>Window</code> class could
  374. directly access the value of <code>x</code>
  375. if L loads <code>Point</code> with the following definition:
  376. <ul><pre>
  377. public class Point {
  378. public int x, y; // not private
  379. public int getX() { return x; }
  380. :
  381. }
  382. </pre></ul>
  383. <p>
  384. For more details of class loaders in Java, the following paper would
  385. be helpful:
  386. <ul>Sheng Liang and Gilad Bracha,
  387. "Dynamic Class Loading in the Java Virtual Machine",
  388. <br><i>ACM OOPSLA'98</i>, pp.36-44, 1998.</ul>
  389. <p><br>
  390. <h3>4.2 Using <code>javassist.Loader</code></h3>
  391. <p>Javassist provides a class loader
  392. <code>javassist.Loader</code>. This class loader uses a
  393. <code>javassist.ClassPool</code> object for reading a class file.
  394. <p>For example, <code>javassist.Loader</code> can be used for loading
  395. a particular class modified with Javassist.
  396. <ul><pre>
  397. import javassist.*;
  398. import test.Rectangle;
  399. public class Main {
  400. public static void main(String[] args) throws Throwable {
  401. ClassPool pool = ClassPool.getDefault();
  402. Loader cl = new Loader(pool);
  403. CtClass ct = pool.get("test.Rectangle");
  404. ct.setSuperclass(pool.get("test.Point"));
  405. Class c = cl.loadClass("test.Rectangle");
  406. Object rect = c.newInstance();
  407. :
  408. }
  409. }
  410. </pre></ul>
  411. <p>This program modifies a class <code>test.Rectangle</code>. The
  412. superclass of <code>test.Rectangle</code> is set to a
  413. <code>test.Point</code> class. Then this program loads the modified
  414. class, and creates a new instance of the
  415. <code>test.Rectangle</code> class.
  416. <p>If the users want to modify a class on demand when it is loaded,
  417. the users can add an event listener to a <code>javassist.Loader</code>.
  418. The added event listener is
  419. notified when the class loader loads a class.
  420. The event-listener class must implement the following interface:
  421. <ul><pre>public interface Translator {
  422. public void start(ClassPool pool)
  423. throws NotFoundException, CannotCompileException;
  424. public void onWrite(ClassPool pool, String classname)
  425. throws NotFoundException, CannotCompileException;
  426. }</pre></ul>
  427. <p>The method <code>start()</code> is called when this event listener
  428. is added to a <code>javassist.Loader</code> object by
  429. <code>addTranslator()</code> in <code>javassist.Loader</code>. The
  430. method <code>onWrite()</code> is called before
  431. <code>javassist.Loader</code> loads a class. <code>onWrite()</code>
  432. can modify the definition of the loaded class.
  433. <p>For example, the following event listener changes all classes
  434. to public classes just before they are loaded.
  435. <ul><pre>public class MyTranslator implements Translator {
  436. void start(ClassPool pool)
  437. throws NotFoundException, CannotCompileException {}
  438. void onWrite(ClassPool pool, String classname)
  439. throws NotFoundException, CannotCompileException
  440. {
  441. CtClass cc = pool.get(classname);
  442. cc.setModifiers(Modifier.PUBLIC);
  443. }
  444. }</pre></ul>
  445. <p>Note that <code>onWrite()</code> does not have to call
  446. <code>toBytecode()</code> or <code>writeFile()</code> since
  447. <code>javassist.Loader</code> calls these methods to obtain a class
  448. file.
  449. <p>To run an application class <code>MyApp</code> with a
  450. <code>MyTranslator</code> object, write a main class as following:
  451. <ul><pre>
  452. import javassist.*;
  453. public class Main2 {
  454. public static void main(String[] args) throws Throwable {
  455. Translator t = new MyTranslator();
  456. ClassPool pool = ClassPool.getDefault();
  457. Loader cl = new Loader();
  458. cl.addTranslator(pool, t);
  459. cl.run("MyApp", args);
  460. }
  461. }
  462. </pre></ul>
  463. <p>To run this program, do:
  464. <ul><pre>
  465. % java Main <i>arg1</i> <i>arg2</i>...
  466. </pre></ul>
  467. <p>The class <code>MyApp</code> and the other application classes
  468. are translated by <code>MyTranslator</code>.
  469. <p>Note that <em>application</em> classes like <code>MyApp</code> cannot
  470. access the <em>loader</em> classes such as <code>Main2</code>,
  471. <code>MyTranslator</code> and <code>ClassPool</code> because they
  472. are loaded by different loaders. The application classes are loaded
  473. by <code>javassist.Loader</code> whereas the loader classes such as
  474. <code>Main</code> are by the default Java class loader.
  475. <p><code>javassist.Loader</code> searches for classes in a different
  476. order from <code>java.lang.ClassLoader</code>.
  477. <code>ClassLoader</code> first delegates the loading operations to
  478. the parent class loader and then attempts to load the classes
  479. only if the parent class loader cannot find them.
  480. On the other hand,
  481. <code>javassist.Loader</code> attempts
  482. to load the classes before delegating to the parent class loader.
  483. It delegates only if:
  484. <ul><li>the classes are not found by calling <code>get()</code> on
  485. a <code>ClassPool</code> object, or
  486. <p><li>the classes have been specified by using
  487. <code>delegateLoadingOf()</code>
  488. to be loaded by the parent class loader.
  489. </ul>
  490. <p>This search order allows loading modified classes by Javassist.
  491. However, it delegates to the parent class loader if it fails
  492. to find modified classes for some reason. Once a class is loaded by
  493. the parent class loader, the other classes referred to in that class will be
  494. also loaded by the parent class loader and thus they are never modified.
  495. Recall that all the classes referred to in a class C are loaded by the
  496. real loader of C.
  497. <em>If your program fails to load a modified class,</em> you should
  498. make sure whether all the classes using that class have been loaded by
  499. <code>javassist.Loader</code>.
  500. <p><br>
  501. <h3>4.3 Writing a class loader</h3>
  502. <p>A simple class loader using Javassist is as follows:
  503. <ul><pre>import javassist.*;
  504. public class SampleLoader extends ClassLoader {
  505. /* Call MyApp.main().
  506. */
  507. public static void main(String[] args) throws Throwable {
  508. SampleLoader s = new SampleLoader();
  509. Class c = s.loadClass("MyApp");
  510. c.getDeclaredMethod("main", new Class[] { String[].class })
  511. .invoke(null, new Object[] { args });
  512. }
  513. private ClassPool pool;
  514. public SampleLoader() throws NotFoundException {
  515. pool = new ClassPool();
  516. pool.insertClassPath("./class"); // <em>MyApp.class must be there.</em>
  517. }
  518. /* Finds a specified class.
  519. * The bytecode for that class can be modified.
  520. */
  521. protected Class findClass(String name) throws ClassNotFoundException {
  522. try {
  523. CtClass cc = pool.get(name);
  524. // <em>modify the CtClass object here</em>
  525. byte[] b = cc.toBytecode();
  526. return defineClass(name, b, 0, b.length);
  527. } catch (NotFoundException e) {
  528. throw new ClassNotFoundException();
  529. } catch (IOException e) {
  530. throw new ClassNotFoundException();
  531. } catch (CannotCompileException e) {
  532. throw new ClassNotFoundException();
  533. }
  534. }
  535. }</pre></ul>
  536. <p>The class <code>MyApp</code> is an application program.
  537. To execute this program, first put the class file under the
  538. <code>./class</code> directory, which must <em>not</em> be included
  539. in the class search path. Otherwise, <code>MyApp.class</code> would
  540. be loaded by the default system class loader, which is the parent
  541. loader of <code>SampleLoader</code>.
  542. The directory name <code>./class</code> is specified by
  543. <code>insertClassPath()</code> in the constructor.
  544. You can choose a different name instead of <code>./class</code> if you want.
  545. Then do as follows:
  546. <ul><code>% java SampleLoader</code></ul>
  547. <p>The class loader loads the class <code>MyApp</code>
  548. (<code>./class/MyApp.class</code>) and calls
  549. <code>MyApp.main()</code> with the command line parameters.
  550. <p>This is the simplest way of using Javassist. However, if you write
  551. a more complex class loader, you may need detailed knowledge of
  552. Java's class loading mechanism. For example, the program above puts the
  553. <code>MyApp</code> class in a name space separated from the name space
  554. that the class <code>SampleLoader</code> belongs to because the two
  555. classes are loaded by different class loaders.
  556. Hence, the
  557. <code>MyApp</code> class cannot directly access the class
  558. <code>SampleLoader</code>.
  559. <p><br>
  560. <h3>4.4 The <code>toClass</code> method in <code>CtClass</code></h3>
  561. <p>The <code>CtClass</code> provides a convenience method
  562. <code>toClass</code>, which loads the class by an internal class
  563. loader of Javassist. This method first obtains the class file
  564. representing the modified class and loads it by an instance of
  565. <code>javassist.ClassPool.SimpleLoader</code>.
  566. The following code is the definition of this class loader:
  567. <ul><pre>
  568. public class SimpleLoader extends ClassLoader {
  569. public Class loadClass(String classname, byte[] classfile)
  570. throws ClassFormatError
  571. {
  572. Class c = defineClass(classname, classfile, 0, classfile.length);
  573. resolveClass(c);
  574. return c;
  575. }
  576. };
  577. </pre></ul>
  578. <p><code>loadClass()</code> loads the class specified by
  579. <code>classfile</code>.
  580. Thus, <code>toClass()</code> is equivalent to the following code:
  581. <ul><pre>
  582. CtClass cc = ... ;
  583. ClassPool.SimpleLoader cl = new ClassPool.SimpleLoader();
  584. Class c = cl.loadClass(cc.getName(), cc.toBytecode());
  585. </pre></ul>
  586. <p>Note that this class loader might be too simple for realistic use.
  587. It delegates to the parent class loader unless the class is explicitly
  588. loaded by <code>loadClass()</code> (or <code>toClass()</code> in
  589. <code>CtClass</code>). If you encounter an unexpected
  590. <code>ClassCastException</code>, you should check the class loader of
  591. the object. Call <code>getClass().getClassLoader()</code> on the
  592. object and make sure that the destination class and the source class
  593. of the cast operation have been loaded by the same class loader.
  594. <p><br>
  595. <h3>4.5 Modifying a system class</h3>
  596. <p>The system classes like <code>java.lang.String</code> cannot be
  597. loaded by a class loader other than the system class loader.
  598. Therefore, <code>SampleLoader</code> or <code>javassist.Loader</code>
  599. shown above cannot modify the system classes at loading time.
  600. <p>If your application needs to do that, the system classes must be
  601. <em>statically</em> modified. For example, the following program
  602. adds a new field <code>hiddenValue</code> to <code>java.lang.String</code>:
  603. <ul><pre>ClassPool pool = ClassPool.getDefault();
  604. CtClass cc = pool.get("java.lang.String");
  605. cc.addField(new CtField(CtClass.intType, "hiddenValue", cc));
  606. pool.writeFile("java.lang.String", ".");</pre></ul>
  607. <p>This program produces a file <code>"./java/lang/String.class"</code>.
  608. <p>To run your program <code>MyApp</code>
  609. with this modified <code>String</code> class, do as follows:
  610. <ul><pre>
  611. % java -Xbootclasspath/p:. MyApp <i>arg1</i> <i>arg2</i>...
  612. </pre></ul>
  613. <p>Suppose that the definition of <code>MyApp</code> is as follows:
  614. <ul><pre>public class MyApp {
  615. public static void main(String[] args) throws Exception {
  616. System.out.println(String.class.getField("hiddenValue").getName());
  617. }
  618. }</pre></ul>
  619. <p>If the modified <code>String</code> class is correctly loaded,
  620. <code>MyApp</code> prints <code>hiddenValue</code>.
  621. <p><i>Note: Applications that use this technique for the purpose of
  622. overriding a system class in <code>rt.jar</code> should not be
  623. deployed as doing so would contravene the Java 2 Runtime Environment
  624. binary code license.</i>
  625. <p><br>
  626. <a href="tutorial2.html">Next page</a>
  627. <hr>
  628. Java(TM) is a trademark of Sun Microsystems, Inc.<br>
  629. Copyright (C) 2000-2004 by Shigeru Chiba, All rights reserved.
  630. </body>
  631. </html>