Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

ProxyFactory.java 60KB

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