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 55KB

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