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.

ProxyFactory.java 49KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.util.proxy;
  16. import java.lang.reflect.Field;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.Member;
  21. import java.lang.reflect.Modifier;
  22. import java.security.ProtectionDomain;
  23. import java.util.*;
  24. import java.lang.ref.WeakReference;
  25. import javassist.CannotCompileException;
  26. import javassist.bytecode.*;
  27. /*
  28. * This class is implemented only with the lower-level API of Javassist.
  29. * This design decision is for maximizing performance.
  30. */
  31. /**
  32. * Factory of dynamic proxy classes.
  33. *
  34. * <p>This factory generates a class that extends the given super class and implements
  35. * the given interfaces. The calls of the methods inherited from the super class are
  36. * forwarded and then <code>invoke()</code> is called on the method handler
  37. * associated with instances of the generated class. The calls of the methods from
  38. * the interfaces are also forwarded to the method handler.
  39. *
  40. * <p>For example, if the following code is executed,
  41. *
  42. * <ul><pre>
  43. * ProxyFactory f = new ProxyFactory();
  44. * f.setSuperclass(Foo.class);
  45. * f.setFilter(new MethodFilter() {
  46. * public boolean isHandled(Method m) {
  47. * // ignore finalize()
  48. * return !m.getName().equals("finalize");
  49. * }
  50. * });
  51. * Class c = f.createClass();
  52. * MethodHandler mi = new MethodHandler() {
  53. * public Object invoke(Object self, Method m, Method proceed,
  54. * Object[] args) throws Throwable {
  55. * System.out.println("Name: " + m.getName());
  56. * return proceed.invoke(self, args); // execute the original method.
  57. * }
  58. * };
  59. * Foo foo = (Foo)c.newInstance();
  60. * ((ProxyObject)foo).setHandler(mi);
  61. * </pre></ul>
  62. *
  63. * <p>Then, the following method call will be forwarded to MethodHandler
  64. * <code>mi</code> and prints a message before executing the originally called method
  65. * <code>bar()</code> in <code>Foo</code>.
  66. *
  67. * <ul><pre>
  68. * foo.bar();
  69. * </pre></ul>
  70. *
  71. * <p>The last three lines of the code shown above can be replaced with a call to
  72. * the helper method <code>create</code>, which generates a proxy class, instantiates
  73. * it, and sets the method handler of the instance:
  74. *
  75. * <ul><pre>
  76. * :
  77. * Foo foo = (Foo)f.create(new Class[0], new Object[0], mi);
  78. * </pre></ul>
  79. *
  80. * <p>To change the method handler during runtime,
  81. * execute the following code:
  82. *
  83. * <ul><pre>
  84. * MethodHandler mi = ... ; // alternative handler
  85. * ((ProxyObject)foo).setHandler(mi);
  86. * </pre></ul>
  87. *
  88. * <p> If setHandler is never called for a proxy instance then it will
  89. * employ the default handler which proceeds by invoking the original method.
  90. * The behaviour of the default handler is identical to the following
  91. * handler:
  92. *
  93. * <ul><pre>
  94. * class EmptyHandler implements MethodHandler {
  95. * public Object invoke(Object self, Method m,
  96. * Method proceed, Object[] args) throws Exception {
  97. * return proceed.invoke(self, args);
  98. * }
  99. * }
  100. * </pre></ul>
  101. *
  102. * <p>A proxy factory caches and reuses proxy classes by default. It is possible to reset
  103. * this default globally by setting static field {@link ProxyFactory#useCache} to false.
  104. * Caching may also be configured for a specific factory by calling instance method
  105. * {@link ProxyFactory#setUseCache(boolean)}. It is strongly recommended that new clients
  106. * of class ProxyFactory enable caching. Failure to do so may lead to exhaustion of
  107. * the heap memory area used to store classes.
  108. *
  109. * <p>Caching is automatically disabled for any given proxy factory if deprecated instance
  110. * method {@link ProxyFactory#setHandler(MethodHandler)} is called. This method was
  111. * used to specify a default handler which newly created proxy classes should install
  112. * when they create their instances. It is only retained to provide backward compatibility
  113. * with previous releases of javassist. Unfortunately,this legacy behaviour makes caching
  114. * and reuse of proxy classes impossible. The current programming model expects javassist
  115. * clients to set the handler of a proxy instance explicitly by calling method
  116. * {@link ProxyObject#setHandler(MethodHandler)} as shown in the sample code above. New
  117. * clients are strongly recommended to use this model rather than calling
  118. * {@link ProxyFactory#setHandler(MethodHandler)}.
  119. *
  120. * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
  121. * if its super class or any of its interfaces implement <code>java.io.Serializable</code>.
  122. * However, a serialized proxy object may not be compatible with future releases.
  123. * The serialization support should be used for short-term storage or RMI.
  124. *
  125. * <p>For compatibility with older releases serialization of proxy objects is implemented by
  126. * adding a writeReplace method to the proxy class. This allows a proxy to be serialized
  127. * to a conventional {@link java.io.ObjectOutputStream} and deserialized from a corresponding
  128. * {@link java.io.ObjectInputStream}. However this method suffers from several problems, the most
  129. * notable one being that it fails to serialize state inherited from the proxy's superclass.
  130. * <p>
  131. * An alternative method of serializing proxy objects is available which fixes these problems. It
  132. * requires inhibiting generation of the writeReplace method and instead using instances of
  133. * {@link javassist.util.proxy.ProxyObjectOutputStream} and {@link javassist.util.proxy.ProxyObjectInputStream}
  134. * (which are subclasses of {@link java.io.ObjectOutputStream} and {@link java.io.ObjectInputStream})
  135. * to serialize and deserialize, respectively, the proxy. These streams recognise javassist proxies and ensure
  136. * that they are serialized and deserialized without the need for the proxy class to implement special methods
  137. * such as writeReplace. Generation of the writeReplace method can be disabled globally by setting static field
  138. * {@link ProxyFactory#useWriteReplace} to false. Alternatively, it may be
  139. * configured per factory by calling instance method {@link ProxyFactory#setUseWriteReplace(boolean)}.
  140. *
  141. * @see MethodHandler
  142. * @since 3.1
  143. * @author Muga Nishizawa
  144. * @author Shigeru Chiba
  145. * @author Andrew Dinn
  146. */
  147. public class ProxyFactory {
  148. private Class superClass;
  149. private Class[] interfaces;
  150. private MethodFilter methodFilter;
  151. private MethodHandler handler; // retained for legacy usage
  152. private List signatureMethods;
  153. private byte[] signature;
  154. private String classname;
  155. private String superName;
  156. private String packageName;
  157. private Class thisClass;
  158. /**
  159. * per factory setting initialised from current setting for useCache but able to be reset before each create call
  160. */
  161. private boolean factoryUseCache;
  162. /**
  163. * per factory setting initialised from current setting for useWriteReplace but able to be reset before each create call
  164. */
  165. private boolean factoryWriteReplace;
  166. /**
  167. * If the value of this variable is not null, the class file of
  168. * the generated proxy class is written under the directory specified
  169. * by this variable. For example, if the value is
  170. * <code>"."</code>, then the class file is written under the current
  171. * directory. This method is for debugging.
  172. *
  173. * <p>The default value is null.
  174. */
  175. public String writeDirectory;
  176. private static final Class OBJECT_TYPE = Object.class;
  177. private static final String HOLDER = "_methods_";
  178. private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
  179. private static final String FILTER_SIGNATURE_FIELD = "_filter_signature";
  180. private static final String FILTER_SIGNATURE_TYPE = "[B";
  181. private static final String HANDLER = "handler";
  182. private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
  183. private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
  184. private static final String HANDLER_TYPE
  185. = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';
  186. private static final String HANDLER_SETTER = "setHandler";
  187. private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
  188. private static final String HANDLER_GETTER = "getHandler";
  189. private static final String HANDLER_GETTER_TYPE = "()" + HANDLER_TYPE;
  190. private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID";
  191. private static final String SERIAL_VERSION_UID_TYPE = "J";
  192. private static final int SERIAL_VERSION_UID_VALUE = -1;
  193. /**
  194. * If true, a generated proxy class is cached and it will be reused
  195. * when generating the proxy class with the same properties is requested.
  196. * The default value is true.
  197. *
  198. * Note that this value merely specifies the initial setting employed by any newly created
  199. * proxy factory. The factory setting may be overwritten by calling factory instance method
  200. * {@link #setUseCache(boolean)}
  201. *
  202. * @since 3.4
  203. */
  204. public static volatile boolean useCache = true;
  205. /**
  206. * If true, a generated proxy class will implement method writeReplace enabling
  207. * serialization of its proxies to a conventional ObjectOutputStream. this (default)
  208. * setting retains the old javassist behaviour which has the advantage that it
  209. * retains compatibility with older releases and requires no extra work on the part
  210. * of the client performing the serialization. However, it has the disadvantage that
  211. * state inherited from the superclasses of the proxy is lost during serialization.
  212. * if false then serialization/deserialization of the proxy instances will preserve
  213. * all fields. However, serialization must be performed via a {@link ProxyObjectOutputStream}
  214. * and deserialization must be via {@link ProxyObjectInputStream}. Any attempt to serialize
  215. * proxies whose class was created with useWriteReplace set to false via a normal
  216. * {@link java.io.ObjectOutputStream} will fail.
  217. *
  218. * Note that this value merely specifies the initial setting employed by any newly created
  219. * proxy factory. The factory setting may be overwritten by calling factory instance method
  220. * {@link #setUseWriteReplace(boolean)}
  221. *
  222. * @since 3.4
  223. */
  224. public static volatile boolean useWriteReplace = true;
  225. /*
  226. * methods allowing individual factory settings for factoryUseCache and factoryWriteReplace to be reset
  227. */
  228. /**
  229. * test whether this factory uses the proxy cache
  230. * @return true if this factory uses the proxy cache otherwise false
  231. */
  232. public boolean isUseCache()
  233. {
  234. return factoryUseCache;
  235. }
  236. /**
  237. * configure whether this factory should use the proxy cache
  238. * @param useCache true if this factory should use the proxy cache and false if it should not use the cache
  239. * @throws RuntimeException if a default interceptor has been set for the factory
  240. */
  241. public void setUseCache(boolean useCache)
  242. {
  243. // we cannot allow caching to be used if the factory is configured to install a default interceptor
  244. // field into generated classes
  245. if (handler != null && useCache) {
  246. throw new RuntimeException("caching cannot be enabled if the factory default interceptor has been set");
  247. }
  248. factoryUseCache = useCache;
  249. }
  250. /**
  251. * test whether this factory installs a writeReplace method in created classes
  252. * @return true if this factory installs a writeReplace method in created classes otherwise false
  253. */
  254. public boolean isUseWriteReplace()
  255. {
  256. return factoryWriteReplace;
  257. }
  258. /**
  259. * configure whether this factory should add a writeReplace method to created classes
  260. * @param useWriteReplace true if this factory should add a writeReplace method to created classes and false if it
  261. * should not add a writeReplace method
  262. */
  263. public void setUseWriteReplace(boolean useWriteReplace)
  264. {
  265. factoryWriteReplace = useWriteReplace;
  266. }
  267. private static WeakHashMap proxyCache = new WeakHashMap();
  268. /**
  269. * determine if a class is a javassist proxy class
  270. * @param cl
  271. * @return true if the class is a javassist proxy class otherwise false
  272. */
  273. public static boolean isProxyClass(Class cl)
  274. {
  275. // all proxies implement ProxyObject. nothing else should.
  276. return (ProxyObject.class.isAssignableFrom(cl));
  277. }
  278. /**
  279. * used to store details of a specific proxy class in the second tier of the proxy cache. this entry
  280. * will be located in a hashmap keyed by the unique identifying name of the proxy class. the hashmap is
  281. * located in a weak hashmap keyed by the classloader common to all proxy classes in the second tier map.
  282. */
  283. static class ProxyDetails {
  284. /**
  285. * the unique signature of any method filter whose behaviour will be met by this class. each bit in
  286. * the byte array is set if the filter redirects the corresponding super or interface method and clear
  287. * if it does not redirect it.
  288. */
  289. byte[] signature;
  290. /**
  291. * a hexadecimal string representation of the signature bit sequence. this string also forms part
  292. * of the proxy class name.
  293. */
  294. WeakReference proxyClass;
  295. /**
  296. * a flag which is true this class employs writeReplace to perform serialization of its instances
  297. * and false if serialization must employ of a ProxyObjectOutputStream and ProxyObjectInputStream
  298. */
  299. boolean isUseWriteReplace;
  300. ProxyDetails(byte[] signature, Class proxyClass, boolean isUseWriteReplace)
  301. {
  302. this.signature = signature;
  303. this.proxyClass = new WeakReference(proxyClass);
  304. this.isUseWriteReplace = isUseWriteReplace;
  305. }
  306. }
  307. /**
  308. * Constructs a factory of proxy class.
  309. */
  310. public ProxyFactory() {
  311. superClass = null;
  312. interfaces = null;
  313. methodFilter = null;
  314. handler = null;
  315. signature = null;
  316. signatureMethods = null;
  317. thisClass = null;
  318. writeDirectory = null;
  319. factoryUseCache = useCache;
  320. factoryWriteReplace = useWriteReplace;
  321. }
  322. /**
  323. * Sets the super class of a proxy class.
  324. */
  325. public void setSuperclass(Class clazz) {
  326. superClass = clazz;
  327. // force recompute of signature
  328. signature = null;
  329. }
  330. /**
  331. * Obtains the super class set by <code>setSuperclass()</code>.
  332. *
  333. * @since 3.4
  334. */
  335. public Class getSuperclass() { return superClass; }
  336. /**
  337. * Sets the interfaces of a proxy class.
  338. */
  339. public void setInterfaces(Class[] ifs) {
  340. interfaces = ifs;
  341. // force recompute of signature
  342. signature = null;
  343. }
  344. /**
  345. * Obtains the interfaces set by <code>setInterfaces</code>.
  346. *
  347. * @since 3.4
  348. */
  349. public Class[] getInterfaces() { return interfaces; }
  350. /**
  351. * Sets a filter that selects the methods that will be controlled by a handler.
  352. */
  353. public void setFilter(MethodFilter mf) {
  354. methodFilter = mf;
  355. // force recompute of signature
  356. signature = null;
  357. }
  358. /**
  359. * Generates a proxy class using the current filter.
  360. */
  361. public Class createClass() {
  362. if (signature == null) {
  363. computeSignature(methodFilter);
  364. }
  365. return createClass1();
  366. }
  367. /**
  368. * Generates a proxy class using the supplied filter.
  369. */
  370. public Class createClass(MethodFilter filter) {
  371. computeSignature(filter);
  372. return createClass1();
  373. }
  374. /**
  375. * Generates a proxy class with a specific signature.
  376. * access is package local so ProxyObjectInputStream can use this
  377. * @param signature
  378. * @return
  379. */
  380. Class createClass(byte[] signature)
  381. {
  382. installSignature(signature);
  383. return createClass1();
  384. }
  385. private Class createClass1() {
  386. if (thisClass == null) {
  387. ClassLoader cl = getClassLoader();
  388. synchronized (proxyCache) {
  389. if (factoryUseCache)
  390. createClass2(cl);
  391. else
  392. createClass3(cl);
  393. }
  394. }
  395. // don't retain any unwanted references
  396. Class result = thisClass;
  397. thisClass = null;
  398. return result;
  399. }
  400. private static char[] hexDigits =
  401. { '0', '1', '2', '3', '4', '5', '6', '7',
  402. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  403. public String getKey(Class superClass, Class[] interfaces, byte[] signature, boolean useWriteReplace)
  404. {
  405. StringBuffer sbuf = new StringBuffer();
  406. if (superClass != null){
  407. sbuf.append(superClass.getName());
  408. }
  409. sbuf.append(":");
  410. for (int i = 0; i < interfaces.length; i++) {
  411. sbuf.append(interfaces[i].getName());
  412. sbuf.append(":");
  413. }
  414. for (int i = 0; i < signature.length; i++) {
  415. byte b = signature[i];
  416. int lo = b & 0xf;
  417. int hi = (b >> 4) & 0xf;
  418. sbuf.append(hexDigits[lo]);
  419. sbuf.append(hexDigits[hi]);
  420. }
  421. if (useWriteReplace) {
  422. sbuf.append(":w");
  423. }
  424. return sbuf.toString();
  425. }
  426. private void createClass2(ClassLoader cl) {
  427. String key = getKey(superClass, interfaces, signature, factoryWriteReplace);
  428. /*
  429. * Excessive concurrency causes a large memory footprint and slows the
  430. * execution speed down (with JDK 1.5). Thus, we use a jumbo lock for
  431. * reducing concrrency.
  432. */
  433. // synchronized (proxyCache) {
  434. HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
  435. ProxyDetails details;
  436. if (cacheForTheLoader == null) {
  437. cacheForTheLoader = new HashMap();
  438. proxyCache.put(cl, cacheForTheLoader);
  439. }
  440. details = (ProxyDetails)cacheForTheLoader.get(key);
  441. if (details != null) {
  442. WeakReference reference = details.proxyClass;
  443. thisClass = (Class)reference.get();
  444. if (thisClass != null) {
  445. return;
  446. }
  447. }
  448. createClass3(cl);
  449. details = new ProxyDetails(signature, thisClass, factoryWriteReplace);
  450. cacheForTheLoader.put(key, details);
  451. // }
  452. }
  453. private void createClass3(ClassLoader cl) {
  454. // we need a new class so we need a new class name
  455. allocateClassName();
  456. try {
  457. ClassFile cf = make();
  458. if (writeDirectory != null)
  459. FactoryHelper.writeFile(cf, writeDirectory);
  460. thisClass = FactoryHelper.toClass(cf, cl, getDomain());
  461. setField(FILTER_SIGNATURE_FIELD, signature);
  462. // legacy behaviour : we only set the default interceptor static field if we are not using the cache
  463. if (!factoryUseCache) {
  464. setField(DEFAULT_INTERCEPTOR, handler);
  465. }
  466. }
  467. catch (CannotCompileException e) {
  468. throw new RuntimeException(e.getMessage(), e);
  469. }
  470. }
  471. private void setField(String fieldName, Object value) {
  472. if (thisClass != null && value != null)
  473. try {
  474. Field f = thisClass.getField(fieldName);
  475. SecurityActions.setAccessible(f, true);
  476. f.set(null, value);
  477. SecurityActions.setAccessible(f, false);
  478. }
  479. catch (Exception e) {
  480. throw new RuntimeException(e);
  481. }
  482. }
  483. static byte[] getFilterSignature(Class clazz) {
  484. return (byte[])getField(clazz, FILTER_SIGNATURE_FIELD);
  485. }
  486. private static Object getField(Class clazz, String fieldName) {
  487. try {
  488. Field f = clazz.getField(fieldName);
  489. f.setAccessible(true);
  490. Object value = f.get(null);
  491. f.setAccessible(false);
  492. return value;
  493. }
  494. catch (Exception e) {
  495. throw new RuntimeException(e);
  496. }
  497. }
  498. /**
  499. * A provider of class loaders.
  500. *
  501. * @see #classLoaderProvider
  502. * @since 3.4
  503. */
  504. public static interface ClassLoaderProvider {
  505. /**
  506. * Returns a class loader.
  507. *
  508. * @param pf a proxy factory that is going to obtain a class loader.
  509. */
  510. public ClassLoader get(ProxyFactory pf);
  511. }
  512. /**
  513. * A provider used by <code>createClass()</code> for obtaining
  514. * a class loader.
  515. * <code>get()</code> on this <code>ClassLoaderProvider</code> object
  516. * is called to obtain a class loader.
  517. *
  518. * <p>The value of this field can be updated for changing the default
  519. * implementation.
  520. *
  521. * <p>Example:
  522. * <ul><pre>
  523. * ProxyFactory.classLoaderProvider = new ProxyFactory.ClassLoaderProvider() {
  524. * public ClassLoader get(ProxyFactory pf) {
  525. * return Thread.currentThread().getContextClassLoader();
  526. * }
  527. * };
  528. * </pre></ul>
  529. *
  530. * @since 3.4
  531. */
  532. public static ClassLoaderProvider classLoaderProvider
  533. = new ClassLoaderProvider() {
  534. public ClassLoader get(ProxyFactory pf) {
  535. return pf.getClassLoader0();
  536. }
  537. };
  538. protected ClassLoader getClassLoader() {
  539. return classLoaderProvider.get(this);
  540. }
  541. protected ClassLoader getClassLoader0() {
  542. ClassLoader loader = null;
  543. if (superClass != null && !superClass.getName().equals("java.lang.Object"))
  544. loader = superClass.getClassLoader();
  545. else if (interfaces != null && interfaces.length > 0)
  546. loader = interfaces[0].getClassLoader();
  547. if (loader == null) {
  548. loader = getClass().getClassLoader();
  549. // In case javassist is in the endorsed dir
  550. if (loader == null) {
  551. loader = Thread.currentThread().getContextClassLoader();
  552. if (loader == null)
  553. loader = ClassLoader.getSystemClassLoader();
  554. }
  555. }
  556. return loader;
  557. }
  558. protected ProtectionDomain getDomain() {
  559. Class clazz;
  560. if (superClass != null && !superClass.getName().equals("java.lang.Object"))
  561. clazz = superClass;
  562. else if (interfaces != null && interfaces.length > 0)
  563. clazz = interfaces[0];
  564. else
  565. clazz = this.getClass();
  566. return clazz.getProtectionDomain();
  567. }
  568. /**
  569. * Creates a proxy class and returns an instance of that class.
  570. *
  571. * @param paramTypes parameter types for a constructor.
  572. * @param args arguments passed to a constructor.
  573. * @param mh the method handler for the proxy class.
  574. * @since 3.4
  575. */
  576. public Object create(Class[] paramTypes, Object[] args, MethodHandler mh)
  577. throws NoSuchMethodException, IllegalArgumentException,
  578. InstantiationException, IllegalAccessException, InvocationTargetException
  579. {
  580. Object obj = create(paramTypes, args);
  581. ((ProxyObject)obj).setHandler(mh);
  582. return obj;
  583. }
  584. /**
  585. * Creates a proxy class and returns an instance of that class.
  586. *
  587. * @param paramTypes parameter types for a constructor.
  588. * @param args arguments passed to a constructor.
  589. */
  590. public Object create(Class[] paramTypes, Object[] args)
  591. throws NoSuchMethodException, IllegalArgumentException,
  592. InstantiationException, IllegalAccessException, InvocationTargetException
  593. {
  594. Class c = createClass();
  595. Constructor cons = c.getConstructor(paramTypes);
  596. return cons.newInstance(args);
  597. }
  598. /**
  599. * Sets the default invocation handler. This invocation handler is shared
  600. * among all the instances of a proxy class unless another is explicitly
  601. * specified.
  602. * @deprecated since 3.12
  603. * use of this method is incompatible with proxy class caching.
  604. * instead clients should call method {@link ProxyObject#setHandler(MethodHandler)} to set the handler
  605. * for each newly created proxy instance.
  606. * calling this method will automatically disable caching of classes created by the proxy factory.
  607. */
  608. public void setHandler(MethodHandler mi) {
  609. // if we were using the cache and the handler is non-null then we must stop caching
  610. if (factoryUseCache && mi != null) {
  611. factoryUseCache = false;
  612. // clear any currently held class so we don't try to reuse it or set its handler field
  613. thisClass = null;
  614. }
  615. handler = mi;
  616. // this retains the behaviour of the old code which resets any class we were holding on to
  617. // this is probably not what is wanted
  618. setField(DEFAULT_INTERCEPTOR, handler);
  619. }
  620. private static int counter = 0;
  621. private static synchronized String makeProxyName(String classname) {
  622. return classname + "_$$_javassist_" + counter++;
  623. }
  624. private ClassFile make() throws CannotCompileException {
  625. ClassFile cf = new ClassFile(false, classname, superName);
  626. cf.setAccessFlags(AccessFlag.PUBLIC);
  627. setInterfaces(cf, interfaces);
  628. ConstPool pool = cf.getConstPool();
  629. // legacy: we only add the static field for the default interceptor if caching is disabled
  630. if (!factoryUseCache) {
  631. FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  632. finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
  633. cf.addField(finfo);
  634. }
  635. // handler is per instance
  636. FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
  637. finfo2.setAccessFlags(AccessFlag.PRIVATE);
  638. cf.addField(finfo2);
  639. // filter signature is per class
  640. FieldInfo finfo3 = new FieldInfo(pool, FILTER_SIGNATURE_FIELD, FILTER_SIGNATURE_TYPE);
  641. finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
  642. cf.addField(finfo3);
  643. // the proxy class serial uid must always be a fixed value
  644. FieldInfo finfo4 = new FieldInfo(pool, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
  645. finfo4.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC| AccessFlag.FINAL);
  646. cf.addField(finfo4);
  647. // HashMap allMethods = getMethods(superClass, interfaces);
  648. // int size = allMethods.size();
  649. makeConstructors(classname, cf, pool, classname);
  650. int s = overrideMethods(cf, pool, classname);
  651. addMethodsHolder(cf, pool, classname, s);
  652. addSetter(classname, cf, pool);
  653. addGetter(classname, cf, pool);
  654. if (factoryWriteReplace) {
  655. try {
  656. cf.addMethod(makeWriteReplace(pool));
  657. }
  658. catch (DuplicateMemberException e) {
  659. // writeReplace() is already declared in the super class/interfaces.
  660. }
  661. }
  662. thisClass = null;
  663. return cf;
  664. }
  665. private void checkClassAndSuperName()
  666. {
  667. if (interfaces == null)
  668. interfaces = new Class[0];
  669. if (superClass == null) {
  670. superClass = OBJECT_TYPE;
  671. }
  672. superName = superClass.getName();
  673. if (Modifier.isFinal(superClass.getModifiers()))
  674. throw new RuntimeException(superName + " is final");
  675. packageName = getPackageName(superName);
  676. if (packageName.startsWith("java."))
  677. packageName = "org.javassist.tmp." + packageName;
  678. }
  679. private void allocateClassName()
  680. {
  681. classname = makeProxyName(superName);
  682. if (classname.startsWith("java."))
  683. classname = "org.javassist.tmp." + classname;
  684. }
  685. private static Comparator sorter = new Comparator() {
  686. public int compare(Object o1, Object o2) {
  687. Map.Entry e1 = (Map.Entry)o1;
  688. Map.Entry e2 = (Map.Entry)o2;
  689. String key1 = (String)e1.getKey();
  690. String key2 = (String)e2.getKey();
  691. return key1.compareTo(key2);
  692. }
  693. };
  694. private void makeSortedMethodList()
  695. {
  696. checkClassAndSuperName();
  697. HashMap allMethods = getMethods(superClass, interfaces);
  698. signatureMethods = new ArrayList(allMethods.entrySet());
  699. Collections.sort(signatureMethods, sorter);
  700. }
  701. private void computeSignature(MethodFilter filter) // throws CannotCompileException
  702. {
  703. makeSortedMethodList();
  704. int l = signatureMethods.size();
  705. int maxBytes = ((l + 7) >> 3);
  706. signature = new byte[maxBytes];
  707. for (int idx = 0; idx < l; idx++)
  708. {
  709. Map.Entry e = (Map.Entry)signatureMethods.get(idx);
  710. Method m = (Method)e.getValue();
  711. int mod = m.getModifiers();
  712. if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
  713. && isVisible(mod, packageName, m) && (filter == null || filter.isHandled(m))) {
  714. setBit(signature, idx);
  715. }
  716. }
  717. }
  718. private void installSignature(byte[] signature) // throws CannotCompileException
  719. {
  720. makeSortedMethodList();
  721. int l = signatureMethods.size();
  722. int maxBytes = ((l + 7) >> 3);
  723. if (signature.length != maxBytes) {
  724. throw new RuntimeException("invalid filter signature length for deserialized proxy class");
  725. }
  726. this.signature = signature;
  727. }
  728. private boolean testBit(byte[] signature, int idx)
  729. {
  730. int byteIdx = idx >> 3;
  731. if (byteIdx > signature.length) {
  732. return false;
  733. } else {
  734. int bitIdx = idx & 0x7;
  735. int mask = 0x1 << bitIdx;
  736. int sigByte = signature[byteIdx];
  737. return ((sigByte & mask) != 0);
  738. }
  739. }
  740. private void setBit(byte[] signature, int idx)
  741. {
  742. int byteIdx = idx >> 3;
  743. if (byteIdx < signature.length) {
  744. int bitIdx = idx & 0x7;
  745. int mask = 0x1 << bitIdx;
  746. int sigByte = signature[byteIdx];
  747. signature[byteIdx] = (byte)(sigByte | mask);
  748. }
  749. }
  750. private static void setInterfaces(ClassFile cf, Class[] interfaces) {
  751. String setterIntf = ProxyObject.class.getName();
  752. String[] list;
  753. if (interfaces == null || interfaces.length == 0)
  754. list = new String[] { setterIntf };
  755. else {
  756. list = new String[interfaces.length + 1];
  757. for (int i = 0; i < interfaces.length; i++)
  758. list[i] = interfaces[i].getName();
  759. list[interfaces.length] = setterIntf;
  760. }
  761. cf.setInterfaces(list);
  762. }
  763. private static void addMethodsHolder(ClassFile cf, ConstPool cp,
  764. String classname, int size)
  765. throws CannotCompileException
  766. {
  767. FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
  768. finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
  769. cf.addField(finfo);
  770. MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
  771. minfo.setAccessFlags(AccessFlag.STATIC);
  772. Bytecode code = new Bytecode(cp, 0, 0);
  773. code.addIconst(size * 2);
  774. code.addAnewarray("java.lang.reflect.Method");
  775. code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
  776. // also need to set serial version uid
  777. code.addLconst(-1L);
  778. code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
  779. code.addOpcode(Bytecode.RETURN);
  780. minfo.setCodeAttribute(code.toCodeAttribute());
  781. cf.addMethod(minfo);
  782. }
  783. private static void addSetter(String classname, ClassFile cf, ConstPool cp)
  784. throws CannotCompileException
  785. {
  786. MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
  787. HANDLER_SETTER_TYPE);
  788. minfo.setAccessFlags(AccessFlag.PUBLIC);
  789. Bytecode code = new Bytecode(cp, 2, 2);
  790. code.addAload(0);
  791. code.addAload(1);
  792. code.addPutfield(classname, HANDLER, HANDLER_TYPE);
  793. code.addOpcode(Bytecode.RETURN);
  794. minfo.setCodeAttribute(code.toCodeAttribute());
  795. cf.addMethod(minfo);
  796. }
  797. private static void addGetter(String classname, ClassFile cf, ConstPool cp)
  798. throws CannotCompileException
  799. {
  800. MethodInfo minfo = new MethodInfo(cp, HANDLER_GETTER,
  801. HANDLER_GETTER_TYPE);
  802. minfo.setAccessFlags(AccessFlag.PUBLIC);
  803. Bytecode code = new Bytecode(cp, 1, 1);
  804. code.addAload(0);
  805. code.addGetfield(classname, HANDLER, HANDLER_TYPE);
  806. code.addOpcode(Bytecode.ARETURN);
  807. minfo.setCodeAttribute(code.toCodeAttribute());
  808. cf.addMethod(minfo);
  809. }
  810. private int overrideMethods(ClassFile cf, ConstPool cp, String className)
  811. throws CannotCompileException
  812. {
  813. String prefix = makeUniqueName("_d", signatureMethods);
  814. Iterator it = signatureMethods.iterator();
  815. int index = 0;
  816. while (it.hasNext()) {
  817. Map.Entry e = (Map.Entry)it.next();
  818. String key = (String)e.getKey();
  819. Method meth = (Method)e.getValue();
  820. int mod = meth.getModifiers();
  821. if (testBit(signature, index)) {
  822. override(className, meth, prefix, index,
  823. keyToDesc(key), cf, cp);
  824. }
  825. index++;
  826. }
  827. return index;
  828. }
  829. private void override(String thisClassname, Method meth, String prefix,
  830. int index, String desc, ClassFile cf, ConstPool cp)
  831. throws CannotCompileException
  832. {
  833. Class declClass = meth.getDeclaringClass();
  834. String delegatorName = prefix + index + meth.getName();
  835. if (Modifier.isAbstract(meth.getModifiers()))
  836. delegatorName = null;
  837. else {
  838. MethodInfo delegator
  839. = makeDelegator(meth, desc, cp, declClass, delegatorName);
  840. // delegator is not a bridge method. See Sec. 15.12.4.5 of JLS 3rd Ed.
  841. delegator.setAccessFlags(delegator.getAccessFlags() & ~AccessFlag.BRIDGE);
  842. cf.addMethod(delegator);
  843. }
  844. MethodInfo forwarder
  845. = makeForwarder(thisClassname, meth, desc, cp, declClass,
  846. delegatorName, index);
  847. cf.addMethod(forwarder);
  848. }
  849. private void makeConstructors(String thisClassName, ClassFile cf,
  850. ConstPool cp, String classname) throws CannotCompileException
  851. {
  852. Constructor[] cons = SecurityActions.getDeclaredConstructors(superClass);
  853. // legacy: if we are not caching then we need to initialise the default handler
  854. boolean doHandlerInit = !factoryUseCache;
  855. for (int i = 0; i < cons.length; i++) {
  856. Constructor c = cons[i];
  857. int mod = c.getModifiers();
  858. if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
  859. && isVisible(mod, packageName, c)) {
  860. MethodInfo m = makeConstructor(thisClassName, c, cp, superClass, doHandlerInit);
  861. cf.addMethod(m);
  862. }
  863. }
  864. }
  865. private static String makeUniqueName(String name, List sortedMethods) {
  866. if (makeUniqueName0(name, sortedMethods.iterator()))
  867. return name;
  868. for (int i = 100; i < 999; i++) {
  869. String s = name + i;
  870. if (makeUniqueName0(s, sortedMethods.iterator()))
  871. return s;
  872. }
  873. throw new RuntimeException("cannot make a unique method name");
  874. }
  875. private static boolean makeUniqueName0(String name, Iterator it) {
  876. while (it.hasNext()) {
  877. Map.Entry e = (Map.Entry)it.next();
  878. String key = (String)e.getKey();
  879. if (key.startsWith(name))
  880. return false;
  881. }
  882. return true;
  883. }
  884. /**
  885. * Returns true if the method is visible from the package.
  886. *
  887. * @param mod the modifiers of the method.
  888. */
  889. private static boolean isVisible(int mod, String fromPackage, Member meth) {
  890. if ((mod & Modifier.PRIVATE) != 0)
  891. return false;
  892. else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
  893. return true;
  894. else {
  895. String q = getPackageName(meth.getDeclaringClass().getName());
  896. if (fromPackage == null)
  897. return q == null;
  898. else
  899. return fromPackage.equals(q);
  900. }
  901. }
  902. private static String getPackageName(String name) {
  903. int i = name.lastIndexOf('.');
  904. if (i < 0)
  905. return null;
  906. else
  907. return name.substring(0, i);
  908. }
  909. private static HashMap getMethods(Class superClass, Class[] interfaceTypes) {
  910. HashMap hash = new HashMap();
  911. for (int i = 0; i < interfaceTypes.length; i++)
  912. getMethods(hash, interfaceTypes[i]);
  913. getMethods(hash, superClass);
  914. return hash;
  915. }
  916. private static void getMethods(HashMap hash, Class clazz) {
  917. Class[] ifs = clazz.getInterfaces();
  918. for (int i = 0; i < ifs.length; i++)
  919. getMethods(hash, ifs[i]);
  920. Class parent = clazz.getSuperclass();
  921. if (parent != null)
  922. getMethods(hash, parent);
  923. Method[] methods = SecurityActions.getDeclaredMethods(clazz);
  924. for (int i = 0; i < methods.length; i++)
  925. if (!Modifier.isPrivate(methods[i].getModifiers())) {
  926. Method m = methods[i];
  927. String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);
  928. // JIRA JASSIST-85
  929. // put the method to the cache, retrieve previous definition (if any)
  930. Method oldMethod = (Method)hash.put(key, methods[i]);
  931. // check if visibility has been reduced
  932. if (null != oldMethod && Modifier.isPublic(oldMethod.getModifiers())
  933. && !Modifier.isPublic(methods[i].getModifiers()) ) {
  934. // we tried to overwrite a public definition with a non-public definition,
  935. // use the old definition instead.
  936. hash.put(key, oldMethod);
  937. }
  938. }
  939. }
  940. private static String keyToDesc(String key) {
  941. return key.substring(key.indexOf(':') + 1);
  942. }
  943. private static MethodInfo makeConstructor(String thisClassName, Constructor cons,
  944. ConstPool cp, Class superClass, boolean doHandlerInit) {
  945. String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),
  946. Void.TYPE);
  947. MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
  948. minfo.setAccessFlags(Modifier.PUBLIC); // cons.getModifiers() & ~Modifier.NATIVE
  949. setThrows(minfo, cp, cons.getExceptionTypes());
  950. Bytecode code = new Bytecode(cp, 0, 0);
  951. // legacy: if we are not using caching then we initialise the instance's handler
  952. // from the class's static default interceptor and skip the next few instructions if
  953. // it is non-null
  954. if (doHandlerInit) {
  955. code.addAload(0);
  956. code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  957. code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
  958. code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  959. code.addOpcode(Opcode.IFNONNULL);
  960. code.addIndex(10);
  961. }
  962. // if caching is enabled then we don't have a handler to initialise so this else branch will install
  963. // the handler located in the static field of class RuntimeSupport.
  964. code.addAload(0);
  965. code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
  966. code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
  967. int pc = code.currentPc();
  968. code.addAload(0);
  969. int s = addLoadParameters(code, cons.getParameterTypes(), 1);
  970. code.addInvokespecial(superClass.getName(), "<init>", desc);
  971. code.addOpcode(Opcode.RETURN);
  972. code.setMaxLocals(s + 1);
  973. CodeAttribute ca = code.toCodeAttribute();
  974. minfo.setCodeAttribute(ca);
  975. StackMapTable.Writer writer = new StackMapTable.Writer(32);
  976. writer.sameFrame(pc);
  977. ca.setAttribute(writer.toStackMapTable(cp));
  978. return minfo;
  979. }
  980. private static MethodInfo makeDelegator(Method meth, String desc,
  981. ConstPool cp, Class declClass, String delegatorName) {
  982. MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
  983. delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
  984. | (meth.getModifiers() & ~(Modifier.PRIVATE
  985. | Modifier.PROTECTED
  986. | Modifier.ABSTRACT
  987. | Modifier.NATIVE
  988. | Modifier.SYNCHRONIZED)));
  989. setThrows(delegator, cp, meth);
  990. Bytecode code = new Bytecode(cp, 0, 0);
  991. code.addAload(0);
  992. int s = addLoadParameters(code, meth.getParameterTypes(), 1);
  993. code.addInvokespecial(declClass.getName(), meth.getName(), desc);
  994. addReturn(code, meth.getReturnType());
  995. code.setMaxLocals(++s);
  996. delegator.setCodeAttribute(code.toCodeAttribute());
  997. return delegator;
  998. }
  999. /**
  1000. * @param delegatorName null if the original method is abstract.
  1001. */
  1002. private static MethodInfo makeForwarder(String thisClassName,
  1003. Method meth, String desc, ConstPool cp,
  1004. Class declClass, String delegatorName, int index) {
  1005. MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
  1006. forwarder.setAccessFlags(Modifier.FINAL
  1007. | (meth.getModifiers() & ~(Modifier.ABSTRACT
  1008. | Modifier.NATIVE
  1009. | Modifier.SYNCHRONIZED)));
  1010. setThrows(forwarder, cp, meth);
  1011. int args = Descriptor.paramSize(desc);
  1012. Bytecode code = new Bytecode(cp, 0, args + 2);
  1013. /*
  1014. * if (methods[index * 2] == null) {
  1015. * methods[index * 2]
  1016. * = RuntimeSupport.findSuperMethod(this, <overridden name>, <desc>);
  1017. * methods[index * 2 + 1]
  1018. * = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
  1019. * or = null // the original method is abstract.
  1020. * }
  1021. * return ($r)handler.invoke(this, methods[index * 2],
  1022. * methods[index * 2 + 1], $args);
  1023. */
  1024. int origIndex = index * 2;
  1025. int delIndex = index * 2 + 1;
  1026. int arrayVar = args + 1;
  1027. code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
  1028. code.addAstore(arrayVar);
  1029. callFind2Methods(code, meth.getName(), delegatorName, origIndex, desc, arrayVar);
  1030. code.addAload(0);
  1031. code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
  1032. code.addAload(0);
  1033. code.addAload(arrayVar);
  1034. code.addIconst(origIndex);
  1035. code.addOpcode(Opcode.AALOAD);
  1036. code.addAload(arrayVar);
  1037. code.addIconst(delIndex);
  1038. code.addOpcode(Opcode.AALOAD);
  1039. makeParameterList(code, meth.getParameterTypes());
  1040. code.addInvokeinterface(MethodHandler.class.getName(), "invoke",
  1041. "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
  1042. 5);
  1043. Class retType = meth.getReturnType();
  1044. addUnwrapper(code, retType);
  1045. addReturn(code, retType);
  1046. CodeAttribute ca = code.toCodeAttribute();
  1047. forwarder.setCodeAttribute(ca);
  1048. return forwarder;
  1049. }
  1050. private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
  1051. Class[] exceptions = orig.getExceptionTypes();
  1052. setThrows(minfo, cp, exceptions);
  1053. }
  1054. private static void setThrows(MethodInfo minfo, ConstPool cp,
  1055. Class[] exceptions) {
  1056. if (exceptions.length == 0)
  1057. return;
  1058. String[] list = new String[exceptions.length];
  1059. for (int i = 0; i < exceptions.length; i++)
  1060. list[i] = exceptions[i].getName();
  1061. ExceptionsAttribute ea = new ExceptionsAttribute(cp);
  1062. ea.setExceptions(list);
  1063. minfo.setExceptionsAttribute(ea);
  1064. }
  1065. private static int addLoadParameters(Bytecode code, Class[] params,
  1066. int offset) {
  1067. int stacksize = 0;
  1068. int n = params.length;
  1069. for (int i = 0; i < n; ++i)
  1070. stacksize += addLoad(code, stacksize + offset, params[i]);
  1071. return stacksize;
  1072. }
  1073. private static int addLoad(Bytecode code, int n, Class type) {
  1074. if (type.isPrimitive()) {
  1075. if (type == Long.TYPE) {
  1076. code.addLload(n);
  1077. return 2;
  1078. }
  1079. else if (type == Float.TYPE)
  1080. code.addFload(n);
  1081. else if (type == Double.TYPE) {
  1082. code.addDload(n);
  1083. return 2;
  1084. }
  1085. else
  1086. code.addIload(n);
  1087. }
  1088. else
  1089. code.addAload(n);
  1090. return 1;
  1091. }
  1092. private static int addReturn(Bytecode code, Class type) {
  1093. if (type.isPrimitive()) {
  1094. if (type == Long.TYPE) {
  1095. code.addOpcode(Opcode.LRETURN);
  1096. return 2;
  1097. }
  1098. else if (type == Float.TYPE)
  1099. code.addOpcode(Opcode.FRETURN);
  1100. else if (type == Double.TYPE) {
  1101. code.addOpcode(Opcode.DRETURN);
  1102. return 2;
  1103. }
  1104. else if (type == Void.TYPE) {
  1105. code.addOpcode(Opcode.RETURN);
  1106. return 0;
  1107. }
  1108. else
  1109. code.addOpcode(Opcode.IRETURN);
  1110. }
  1111. else
  1112. code.addOpcode(Opcode.ARETURN);
  1113. return 1;
  1114. }
  1115. private static void makeParameterList(Bytecode code, Class[] params) {
  1116. int regno = 1;
  1117. int n = params.length;
  1118. code.addIconst(n);
  1119. code.addAnewarray("java/lang/Object");
  1120. for (int i = 0; i < n; i++) {
  1121. code.addOpcode(Opcode.DUP);
  1122. code.addIconst(i);
  1123. Class type = params[i];
  1124. if (type.isPrimitive())
  1125. regno = makeWrapper(code, type, regno);
  1126. else {
  1127. code.addAload(regno);
  1128. regno++;
  1129. }
  1130. code.addOpcode(Opcode.AASTORE);
  1131. }
  1132. }
  1133. private static int makeWrapper(Bytecode code, Class type, int regno) {
  1134. int index = FactoryHelper.typeIndex(type);
  1135. String wrapper = FactoryHelper.wrapperTypes[index];
  1136. code.addNew(wrapper);
  1137. code.addOpcode(Opcode.DUP);
  1138. addLoad(code, regno, type);
  1139. code.addInvokespecial(wrapper, "<init>",
  1140. FactoryHelper.wrapperDesc[index]);
  1141. return regno + FactoryHelper.dataSize[index];
  1142. }
  1143. /**
  1144. * @param thisMethod might be null.
  1145. */
  1146. private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
  1147. int index, String desc, int arrayVar) {
  1148. String findClass = RuntimeSupport.class.getName();
  1149. String findDesc
  1150. = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
  1151. code.addAload(0);
  1152. code.addLdc(superMethod);
  1153. if (thisMethod == null)
  1154. code.addOpcode(Opcode.ACONST_NULL);
  1155. else
  1156. code.addLdc(thisMethod);
  1157. code.addIconst(index);
  1158. code.addLdc(desc);
  1159. code.addAload(arrayVar);
  1160. code.addInvokestatic(findClass, "find2Methods", findDesc);
  1161. }
  1162. private static void addUnwrapper(Bytecode code, Class type) {
  1163. if (type.isPrimitive()) {
  1164. if (type == Void.TYPE)
  1165. code.addOpcode(Opcode.POP);
  1166. else {
  1167. int index = FactoryHelper.typeIndex(type);
  1168. String wrapper = FactoryHelper.wrapperTypes[index];
  1169. code.addCheckcast(wrapper);
  1170. code.addInvokevirtual(wrapper,
  1171. FactoryHelper.unwarpMethods[index],
  1172. FactoryHelper.unwrapDesc[index]);
  1173. }
  1174. }
  1175. else
  1176. code.addCheckcast(type.getName());
  1177. }
  1178. private static MethodInfo makeWriteReplace(ConstPool cp) {
  1179. MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
  1180. String[] list = new String[1];
  1181. list[0] = "java.io.ObjectStreamException";
  1182. ExceptionsAttribute ea = new ExceptionsAttribute(cp);
  1183. ea.setExceptions(list);
  1184. minfo.setExceptionsAttribute(ea);
  1185. Bytecode code = new Bytecode(cp, 0, 1);
  1186. code.addAload(0);
  1187. code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
  1188. "makeSerializedProxy",
  1189. "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
  1190. code.addOpcode(Opcode.ARETURN);
  1191. minfo.setCodeAttribute(code.toCodeAttribute());
  1192. return minfo;
  1193. }
  1194. }