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

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