| GNU Classpath (0.95) | |
| Frames | No Frames |
1: /* Proxy.java -- build a proxy class that implements reflected interfaces 2: Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.lang.reflect; 40: 41: import gnu.java.lang.reflect.TypeSignature; 42: 43: import java.io.Serializable; 44: import java.security.ProtectionDomain; 45: import java.util.Arrays; 46: import java.util.HashMap; 47: import java.util.HashSet; 48: import java.util.Iterator; 49: import java.util.Map; 50: import java.util.Set; 51: 52: /** 53: * This class allows you to dynamically create an instance of any (or 54: * even multiple) interfaces by reflection, and decide at runtime 55: * how that instance will behave by giving it an appropriate 56: * {@link InvocationHandler}. Proxy classes serialize specially, so 57: * that the proxy object can be reused between VMs, without requiring 58: * a persistent copy of the generated class code. 59: * 60: * <h3>Creation</h3> 61: * To create a proxy for some interface Foo: 62: * 63: * <pre> 64: * InvocationHandler handler = new MyInvocationHandler(...); 65: * Class proxyClass = Proxy.getProxyClass( 66: * Foo.class.getClassLoader(), new Class[] { Foo.class }); 67: * Foo f = (Foo) proxyClass 68: * .getConstructor(new Class[] { InvocationHandler.class }) 69: * .newInstance(new Object[] { handler }); 70: * </pre> 71: * or more simply: 72: * <pre> 73: * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), 74: * new Class[] { Foo.class }, 75: * handler); 76: * </pre> 77: * 78: * <h3>Dynamic Proxy Classes</h3> 79: * A dynamic proxy class is created at runtime, and has the following 80: * properties: 81: * <ul> 82: * <li>The class is <code>public</code> and <code>final</code>, 83: * and is neither <code>abstract</code> nor an inner class.</li> 84: * <li>The class has no canonical name (there is no formula you can use 85: * to determine or generate its name), but begins with the 86: * sequence "$Proxy". Abuse this knowledge at your own peril. 87: * (For now, '$' in user identifiers is legal, but it may not 88: * be that way forever. You weren't using '$' in your 89: * identifiers, were you?)</li> 90: * <li>The class extends Proxy, and explicitly implements all the 91: * interfaces specified at creation, in order (this is important 92: * for determining how method invocation is resolved). Note that 93: * a proxy class implements {@link Serializable}, at least 94: * implicitly, since Proxy does, but true serial behavior 95: * depends on using a serializable invocation handler as well.</li> 96: * <li>If at least one interface is non-public, the proxy class 97: * will be in the same package. Otherwise, the package is 98: * unspecified. This will work even if the package is sealed 99: * from user-generated classes, because Proxy classes are 100: * generated by a trusted source. Meanwhile, the proxy class 101: * belongs to the classloader you designated.</li> 102: * <li>Reflection works as expected: {@link Class#getInterfaces()} and 103: * {@link Class#getMethods()} work as they do on normal classes.</li> 104: * <li>The method {@link #isProxyClass(Class)} will distinguish between 105: * true proxy classes and user extensions of this class. It only 106: * returns true for classes created by {@link #getProxyClass}.</li> 107: * <li>The {@link ProtectionDomain} of a proxy class is the same as for 108: * bootstrap classes, such as Object or Proxy, since it is created by 109: * a trusted source. This protection domain will typically be granted 110: * {@link java.security.AllPermission}. But this is not a security 111: * risk, since there are adequate permissions on reflection, which is 112: * the only way to create an instance of the proxy class.</li> 113: * <li>The proxy class contains a single constructor, which takes as 114: * its only argument an {@link InvocationHandler}. The method 115: * {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)} 116: * is shorthand to do the necessary reflection.</li> 117: * </ul> 118: * 119: * <h3>Proxy Instances</h3> 120: * A proxy instance is an instance of a proxy class. It has the 121: * following properties, many of which follow from the properties of a 122: * proxy class listed above: 123: * <ul> 124: * <li>For a proxy class with Foo listed as one of its interfaces, the 125: * expression <code>proxy instanceof Foo</code> will return true, 126: * and the expression <code>(Foo) proxy</code> will succeed without 127: * a {@link ClassCastException}.</li> 128: * <li>Each proxy instance has an invocation handler, which can be 129: * accessed by {@link #getInvocationHandler(Object)}. Any call 130: * to an interface method, including {@link Object#hashCode()}, 131: * {@link Object#equals(Object)}, or {@link Object#toString()}, 132: * but excluding the public final methods of Object, will be 133: * encoded and passed to the {@link InvocationHandler#invoke} 134: * method of this handler.</li> 135: * </ul> 136: * 137: * <h3>Inheritance Issues</h3> 138: * A proxy class may inherit a method from more than one interface. 139: * The order in which interfaces are listed matters, because it determines 140: * which reflected {@link Method} object will be passed to the invocation 141: * handler. This means that the dynamically generated class cannot 142: * determine through which interface a method is being invoked.<p> 143: * 144: * In short, if a method is declared in Object (namely, hashCode, 145: * equals, or toString), then Object will be used; otherwise, the 146: * leftmost interface that inherits or declares a method will be used, 147: * even if it has a more permissive throws clause than what the proxy 148: * class is allowed. Thus, in the invocation handler, it is not always 149: * safe to assume that every class listed in the throws clause of the 150: * passed Method object can safely be thrown; fortunately, the Proxy 151: * instance is robust enough to wrap all illegal checked exceptions in 152: * {@link UndeclaredThrowableException}. 153: * 154: * @see InvocationHandler 155: * @see UndeclaredThrowableException 156: * @see Class 157: * @author Eric Blake (ebb9@email.byu.edu) 158: * @since 1.3 159: * @status updated to 1.5, except for the use of ProtectionDomain 160: */ 161: public class Proxy implements Serializable 162: { 163: /** 164: * Compatible with JDK 1.3+. 165: */ 166: private static final long serialVersionUID = -2222568056686623797L; 167: 168: /** 169: * Map of ProxyType to proxy class. 170: * 171: * @XXX This prevents proxy classes from being garbage collected. 172: * java.util.WeakHashSet is not appropriate, because that collects the 173: * keys, but we are interested in collecting the elements. 174: */ 175: private static final Map proxyClasses = new HashMap(); 176: 177: /** 178: * The invocation handler for this proxy instance. For Proxy, this 179: * field is unused, but it appears here in order to be serialized in all 180: * proxy classes. 181: * 182: * <em>NOTE</em>: This implementation is more secure for proxy classes 183: * than what Sun specifies. Sun does not require h to be immutable, but 184: * this means you could change h after the fact by reflection. However, 185: * by making h immutable, we may break non-proxy classes which extend 186: * Proxy. 187: * @serial invocation handler associated with this proxy instance 188: */ 189: protected InvocationHandler h; 190: 191: /** 192: * Constructs a new Proxy from a subclass (usually a proxy class), 193: * with the specified invocation handler. 194: * 195: * <em>NOTE</em>: This throws a NullPointerException if you attempt 196: * to create a proxy instance with a null handler using reflection. 197: * This behavior is not yet specified by Sun; see Sun Bug 4487672. 198: * 199: * @param handler the invocation handler, may be null if the subclass 200: * is not a proxy class 201: * @throws NullPointerException if handler is null and this is a proxy 202: * instance 203: */ 204: protected Proxy(InvocationHandler handler) 205: { 206: if (handler == null && isProxyClass(getClass())) 207: throw new NullPointerException("invalid handler"); 208: h = handler; 209: } 210: 211: /** 212: * Returns the proxy {@link Class} for the given ClassLoader and array 213: * of interfaces, dynamically generating it if necessary. 214: * 215: * <p>There are several restrictions on this method, the violation of 216: * which will result in an IllegalArgumentException or 217: * NullPointerException:</p> 218: * 219: * <ul> 220: * <li>All objects in `interfaces' must represent distinct interfaces. 221: * Classes, primitive types, null, and duplicates are forbidden.</li> 222: * <li>The interfaces must be visible in the specified ClassLoader. 223: * In other words, for each interface i: 224: * <code>Class.forName(i.getName(), false, loader) == i</code> 225: * must be true.</li> 226: * <li>All non-public interfaces (if any) must reside in the same 227: * package, or the proxy class would be non-instantiable. If 228: * there are no non-public interfaces, the package of the proxy 229: * class is unspecified.</li> 230: * <li>All interfaces must be compatible - if two declare a method 231: * with the same name and parameters, the return type must be 232: * the same and the throws clause of the proxy class will be 233: * the maximal subset of subclasses of the throws clauses for 234: * each method that is overridden.</li> 235: * <li>VM constraints limit the number of interfaces a proxy class 236: * may directly implement (however, the indirect inheritance 237: * of {@link Serializable} does not count against this limit). 238: * Even though most VMs can theoretically have 65535 239: * superinterfaces for a class, the actual limit is smaller 240: * because a class's constant pool is limited to 65535 entries, 241: * and not all entries can be interfaces.</li> 242: * </ul> 243: * 244: * <p>Note that different orders of interfaces produce distinct classes.</p> 245: * 246: * @param loader the class loader to define the proxy class in; null 247: * implies the bootstrap class loader 248: * @param interfaces the array of interfaces the proxy class implements, 249: * may be empty, but not null 250: * @return the Class object of the proxy class 251: * @throws IllegalArgumentException if the constraints above were 252: * violated, except for problems with null 253: * @throws NullPointerException if `interfaces' is null or contains 254: * a null entry 255: */ 256: // synchronized so that we aren't trying to build the same class 257: // simultaneously in two threads 258: public static synchronized Class<?> getProxyClass(ClassLoader loader, 259: Class<?>... interfaces) 260: { 261: interfaces = (Class[]) interfaces.clone(); 262: ProxyType pt = new ProxyType(loader, interfaces); 263: Class clazz = (Class) proxyClasses.get(pt); 264: if (clazz == null) 265: { 266: if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS) 267: clazz = VMProxy.getProxyClass(loader, interfaces); 268: else 269: { 270: ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA 271: ? VMProxy.getProxyData(loader, interfaces) 272: : ProxyData.getProxyData(pt)); 273: 274: clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS 275: ? VMProxy.generateProxyClass(loader, data) 276: : new ClassFactory(data).generate(loader)); 277: } 278: 279: Object check = proxyClasses.put(pt, clazz); 280: // assert check == null && clazz != null; 281: if (check != null || clazz == null) 282: throw new InternalError(/*"Fatal flaw in getProxyClass"*/); 283: } 284: return clazz; 285: } 286: 287: /** 288: * Combines several methods into one. This is equivalent to: 289: * <pre> 290: * Proxy.getProxyClass(loader, interfaces) 291: * .getConstructor(new Class[] {InvocationHandler.class}) 292: * .newInstance(new Object[] {handler}); 293: * </pre> 294: * except that it will not fail with the normal problems caused 295: * by reflection. It can still fail for the same reasons documented 296: * in getProxyClass, or if handler is null. 297: * 298: * @param loader the class loader to define the proxy class in; null 299: * implies the bootstrap class loader 300: * @param interfaces the array of interfaces the proxy class implements, 301: * may be empty, but not null 302: * @param handler the invocation handler, may not be null 303: * @return a proxy instance implementing the specified interfaces 304: * @throws IllegalArgumentException if the constraints for getProxyClass 305: * were violated, except for problems with null 306: * @throws NullPointerException if `interfaces' is null or contains 307: * a null entry, or if handler is null 308: * @see #getProxyClass(ClassLoader, Class[]) 309: * @see Class#getConstructor(Class[]) 310: * @see Constructor#newInstance(Object[]) 311: */ 312: public static Object newProxyInstance(ClassLoader loader, 313: Class<?>[] interfaces, 314: InvocationHandler handler) 315: { 316: try 317: { 318: // getProxyClass() and Proxy() throw the necessary exceptions 319: return getProxyClass(loader, interfaces) 320: .getConstructor(new Class[] {InvocationHandler.class}) 321: .newInstance(new Object[] {handler}); 322: } 323: catch (RuntimeException e) 324: { 325: // Let IllegalArgumentException, NullPointerException escape. 326: // assert e instanceof IllegalArgumentException 327: // || e instanceof NullPointerException; 328: throw e; 329: } 330: catch (InvocationTargetException e) 331: { 332: // Let wrapped NullPointerException escape. 333: // assert e.getTargetException() instanceof NullPointerException 334: throw (NullPointerException) e.getCause(); 335: } 336: catch (Exception e) 337: { 338: // Covers InstantiationException, IllegalAccessException, 339: // NoSuchMethodException, none of which should be generated 340: // if the proxy class was generated correctly. 341: // assert false; 342: throw (Error) new InternalError("Unexpected: " + e).initCause(e); 343: } 344: } 345: 346: /** 347: * Returns true if and only if the Class object is a dynamically created 348: * proxy class (created by <code>getProxyClass</code> or by the 349: * syntactic sugar of <code>newProxyInstance</code>). 350: * 351: * <p>This check is secure (in other words, it is not simply 352: * <code>clazz.getSuperclass() == Proxy.class</code>), it will not 353: * be spoofed by non-proxy classes that extend Proxy. 354: * 355: * @param clazz the class to check, must not be null 356: * @return true if the class represents a proxy class 357: * @throws NullPointerException if clazz is null 358: */ 359: // This is synchronized on the off chance that another thread is 360: // trying to add a class to the map at the same time we read it. 361: public static synchronized boolean isProxyClass(Class<?> clazz) 362: { 363: if (! Proxy.class.isAssignableFrom(clazz)) 364: return false; 365: // This is a linear search, even though we could do an O(1) search 366: // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()). 367: return proxyClasses.containsValue(clazz); 368: } 369: 370: /** 371: * Returns the invocation handler for the given proxy instance.<p> 372: * 373: * <em>NOTE</em>: We guarantee a non-null result if successful, 374: * but Sun allows the creation of a proxy instance with a null 375: * handler. See the comments for {@link #Proxy(InvocationHandler)}. 376: * 377: * @param proxy the proxy instance, must not be null 378: * @return the invocation handler, guaranteed non-null. 379: * @throws IllegalArgumentException if 380: * <code>Proxy.isProxyClass(proxy.getClass())</code> returns false. 381: * @throws NullPointerException if proxy is null 382: */ 383: public static InvocationHandler getInvocationHandler(Object proxy) 384: { 385: if (! isProxyClass(proxy.getClass())) 386: throw new IllegalArgumentException("not a proxy instance"); 387: return ((Proxy) proxy).h; 388: } 389: 390: /** 391: * Helper class for mapping unique ClassLoader and interface combinations 392: * to proxy classes. 393: * 394: * @author Eric Blake (ebb9@email.byu.edu) 395: */ 396: private static final class ProxyType 397: { 398: /** 399: * Store the class loader (may be null) 400: */ 401: final ClassLoader loader; 402: 403: /** 404: * Store the interfaces (never null, all elements are interfaces) 405: */ 406: final Class[] interfaces; 407: 408: /** 409: * Construct the helper object. 410: * 411: * @param loader the class loader to define the proxy class in; null 412: * implies the bootstrap class loader 413: * @param interfaces an array of interfaces 414: */ 415: ProxyType(ClassLoader loader, Class[] interfaces) 416: { 417: this.loader = loader; 418: this.interfaces = interfaces; 419: } 420: 421: /** 422: * Calculates the hash code. 423: * 424: * @return a combination of the classloader and interfaces hashcodes. 425: */ 426: public int hashCode() 427: { 428: int hash = loader == null ? 0 : loader.hashCode(); 429: for (int i = 0; i < interfaces.length; i++) 430: hash = hash * 31 + interfaces[i].hashCode(); 431: return hash; 432: } 433: 434: /** 435: * Calculates equality. 436: * 437: * @param other object to compare to 438: * @return true if it is a ProxyType with same data 439: */ 440: public boolean equals(Object other) 441: { 442: ProxyType pt = (ProxyType) other; 443: if (loader != pt.loader || interfaces.length != pt.interfaces.length) 444: return false; 445: for (int i = 0; i < interfaces.length; i++) 446: if (interfaces[i] != pt.interfaces[i]) 447: return false; 448: return true; 449: } 450: } // class ProxyType 451: 452: /** 453: * Helper class which allows hashing of a method name and signature 454: * without worrying about return type, declaring class, or throws clause, 455: * and which reduces the maximally common throws clause between two methods 456: * 457: * @author Eric Blake (ebb9@email.byu.edu) 458: */ 459: private static final class ProxySignature 460: { 461: /** 462: * The core signatures which all Proxy instances handle. 463: */ 464: static final HashMap coreMethods = new HashMap(); 465: static 466: { 467: try 468: { 469: ProxySignature sig 470: = new ProxySignature(Object.class 471: .getMethod("equals", 472: new Class[] {Object.class})); 473: coreMethods.put(sig, sig); 474: sig = new ProxySignature(Object.class.getMethod("hashCode", null)); 475: coreMethods.put(sig, sig); 476: sig = new ProxySignature(Object.class.getMethod("toString", null)); 477: coreMethods.put(sig, sig); 478: } 479: catch (Exception e) 480: { 481: // assert false; 482: throw (Error) new InternalError("Unexpected: " + e).initCause(e); 483: } 484: } 485: 486: /** 487: * The underlying Method object, never null 488: */ 489: final Method method; 490: 491: /** 492: * The set of compatible thrown exceptions, may be empty 493: */ 494: final Set exceptions = new HashSet(); 495: 496: /** 497: * Construct a signature 498: * 499: * @param method the Method this signature is based on, never null 500: */ 501: ProxySignature(Method method) 502: { 503: this.method = method; 504: Class[] exc = method.getExceptionTypes(); 505: int i = exc.length; 506: while (--i >= 0) 507: { 508: // discard unchecked exceptions 509: if (Error.class.isAssignableFrom(exc[i]) 510: || RuntimeException.class.isAssignableFrom(exc[i])) 511: continue; 512: exceptions.add(exc[i]); 513: } 514: } 515: 516: /** 517: * Given a method, make sure it's return type is identical 518: * to this, and adjust this signature's throws clause appropriately 519: * 520: * @param other the signature to merge in 521: * @throws IllegalArgumentException if the return types conflict 522: */ 523: void checkCompatibility(ProxySignature other) 524: { 525: if (method.getReturnType() != other.method.getReturnType()) 526: throw new IllegalArgumentException("incompatible return types: " 527: + method + ", " + other.method); 528: 529: // if you can think of a more efficient way than this O(n^2) search, 530: // implement it! 531: int size1 = exceptions.size(); 532: int size2 = other.exceptions.size(); 533: boolean[] valid1 = new boolean[size1]; 534: boolean[] valid2 = new boolean[size2]; 535: Iterator itr = exceptions.iterator(); 536: int pos = size1; 537: while (--pos >= 0) 538: { 539: Class c1 = (Class) itr.next(); 540: Iterator itr2 = other.exceptions.iterator(); 541: int pos2 = size2; 542: while (--pos2 >= 0) 543: { 544: Class c2 = (Class) itr2.next(); 545: if (c2.isAssignableFrom(c1)) 546: valid1[pos] = true; 547: if (c1.isAssignableFrom(c2)) 548: valid2[pos2] = true; 549: } 550: } 551: pos = size1; 552: itr = exceptions.iterator(); 553: while (--pos >= 0) 554: { 555: itr.next(); 556: if (! valid1[pos]) 557: itr.remove(); 558: } 559: pos = size2; 560: itr = other.exceptions.iterator(); 561: while (--pos >= 0) 562: { 563: itr.next(); 564: if (! valid2[pos]) 565: itr.remove(); 566: } 567: exceptions.addAll(other.exceptions); 568: } 569: 570: /** 571: * Calculates the hash code. 572: * 573: * @return a combination of name and parameter types 574: */ 575: public int hashCode() 576: { 577: int hash = method.getName().hashCode(); 578: Class[] types = method.getParameterTypes(); 579: for (int i = 0; i < types.length; i++) 580: hash = hash * 31 + types[i].hashCode(); 581: return hash; 582: } 583: 584: /** 585: * Calculates equality. 586: * 587: * @param other object to compare to 588: * @return true if it is a ProxySignature with same data 589: */ 590: public boolean equals(Object other) 591: { 592: ProxySignature ps = (ProxySignature) other; 593: Class[] types1 = method.getParameterTypes(); 594: Class[] types2 = ps.method.getParameterTypes(); 595: if (! method.getName().equals(ps.method.getName()) 596: || types1.length != types2.length) 597: return false; 598: int i = types1.length; 599: while (--i >= 0) 600: if (types1[i] != types2[i]) 601: return false; 602: return true; 603: } 604: } // class ProxySignature 605: 606: /** 607: * A flat representation of all data needed to generate bytecode/instantiate 608: * a proxy class. This is basically a struct. 609: * 610: * @author Eric Blake (ebb9@email.byu.edu) 611: */ 612: static final class ProxyData 613: { 614: /** 615: * The package this class is in <b>including the trailing dot</b> 616: * or an empty string for the unnamed (aka default) package. 617: */ 618: String pack = ""; 619: 620: /** 621: * The interfaces this class implements. Non-null, but possibly empty. 622: */ 623: Class[] interfaces; 624: 625: /** 626: * The Method objects this class must pass as the second argument to 627: * invoke (also useful for determining what methods this class has). 628: * Non-null, non-empty (includes at least Object.hashCode, Object.equals, 629: * and Object.toString). 630: */ 631: Method[] methods; 632: 633: /** 634: * The exceptions that do not need to be wrapped in 635: * UndeclaredThrowableException. exceptions[i] is the same as, or a 636: * subset of subclasses, of methods[i].getExceptionTypes(), depending on 637: * compatible throws clauses with multiple inheritance. It is unspecified 638: * if these lists include or exclude subclasses of Error and 639: * RuntimeException, but excluding them is harmless and generates a 640: * smaller class. 641: */ 642: Class[][] exceptions; 643: 644: /** 645: * For unique id's 646: */ 647: private static int count; 648: 649: /** 650: * The id of this proxy class 651: */ 652: final int id = count++; 653: 654: /** 655: * Construct a ProxyData with uninitialized data members. 656: */ 657: ProxyData() 658: { 659: } 660: 661: /** 662: * Return the name of a package (including the trailing dot) 663: * given the name of a class. 664: * Returns an empty string if no package. We use this in preference to 665: * using Class.getPackage() to avoid problems with ClassLoaders 666: * that don't set the package. 667: */ 668: private static String getPackage(Class k) 669: { 670: String name = k.getName(); 671: int idx = name.lastIndexOf('.'); 672: return name.substring(0, idx + 1); 673: } 674: 675: /** 676: * Verifies that the arguments are legal, and sets up remaining data 677: * This should only be called when a class must be generated, as 678: * it is expensive. 679: * 680: * @param pt the ProxyType to convert to ProxyData 681: * @return the flattened, verified ProxyData structure for use in 682: * class generation 683: * @throws IllegalArgumentException if `interfaces' contains 684: * non-interfaces or incompatible combinations, and verify is true 685: * @throws NullPointerException if interfaces is null or contains null 686: */ 687: static ProxyData getProxyData(ProxyType pt) 688: { 689: Map method_set = (Map) ProxySignature.coreMethods.clone(); 690: boolean in_package = false; // true if we encounter non-public interface 691: 692: ProxyData data = new ProxyData(); 693: data.interfaces = pt.interfaces; 694: 695: // if interfaces is too large, we croak later on when the constant 696: // pool overflows 697: int i = data.interfaces.length; 698: while (--i >= 0) 699: { 700: Class inter = data.interfaces[i]; 701: if (! inter.isInterface()) 702: throw new IllegalArgumentException("not an interface: " + inter); 703: try 704: { 705: if (Class.forName(inter.getName(), false, pt.loader) != inter) 706: throw new IllegalArgumentException("not accessible in " 707: + "classloader: " + inter); 708: } 709: catch (ClassNotFoundException e) 710: { 711: throw new IllegalArgumentException("not accessible in " 712: + "classloader: " + inter); 713: } 714: if (! Modifier.isPublic(inter.getModifiers())) 715: if (in_package) 716: { 717: String p = getPackage(inter); 718: if (! data.pack.equals(p)) 719: throw new IllegalArgumentException("non-public interfaces " 720: + "from different " 721: + "packages"); 722: } 723: else 724: { 725: in_package = true; 726: data.pack = getPackage(inter); 727: } 728: for (int j = i-1; j >= 0; j--) 729: if (data.interfaces[j] == inter) 730: throw new IllegalArgumentException("duplicate interface: " 731: + inter); 732: Method[] methods = inter.getMethods(); 733: int j = methods.length; 734: while (--j >= 0) 735: { 736: if (isCoreObjectMethod(methods[j])) 737: { 738: // In the case of an attempt to redefine a public non-final 739: // method of Object, we must skip it 740: continue; 741: } 742: ProxySignature sig = new ProxySignature(methods[j]); 743: ProxySignature old = (ProxySignature) method_set.put(sig, sig); 744: if (old != null) 745: sig.checkCompatibility(old); 746: } 747: } 748: 749: i = method_set.size(); 750: data.methods = new Method[i]; 751: data.exceptions = new Class[i][]; 752: Iterator itr = method_set.values().iterator(); 753: while (--i >= 0) 754: { 755: ProxySignature sig = (ProxySignature) itr.next(); 756: data.methods[i] = sig.method; 757: data.exceptions[i] = (Class[]) sig.exceptions 758: .toArray(new Class[sig.exceptions.size()]); 759: } 760: return data; 761: } 762: 763: /** 764: * Checks whether the method is similar to a public non-final method of 765: * Object or not (i.e. with the same name and parameter types). Note that we 766: * can't rely, directly or indirectly (via Collection.contains) on 767: * Method.equals as it would also check the declaring class, what we do not 768: * want. We only want to check that the given method have the same signature 769: * as a core method (same name and parameter types) 770: * 771: * @param method the method to check 772: * @return whether the method has the same name and parameter types as 773: * Object.equals, Object.hashCode or Object.toString 774: * @see java.lang.Object#equals(Object) 775: * @see java.lang.Object#hashCode() 776: * @see java.lang.Object#toString() 777: */ 778: private static boolean isCoreObjectMethod(Method method) 779: { 780: String methodName = method.getName(); 781: if (methodName.equals("equals")) 782: { 783: return Arrays.equals(method.getParameterTypes(), 784: new Class[] { Object.class }); 785: } 786: if (methodName.equals("hashCode")) 787: { 788: return method.getParameterTypes().length == 0; 789: } 790: if (methodName.equals("toString")) 791: { 792: return method.getParameterTypes().length == 0; 793: } 794: return false; 795: } 796: 797: } // class ProxyData 798: 799: /** 800: * Does all the work of building a class. By making this a nested class, 801: * this code is not loaded in memory if the VM has a native 802: * implementation instead. 803: * 804: * @author Eric Blake (ebb9@email.byu.edu) 805: */ 806: private static final class ClassFactory 807: { 808: /** Constants for assisting the compilation */ 809: private static final byte FIELD = 1; 810: private static final byte METHOD = 2; 811: private static final byte INTERFACE = 3; 812: private static final String CTOR_SIG 813: = "(Ljava/lang/reflect/InvocationHandler;)V"; 814: private static final String INVOKE_SIG = "(Ljava/lang/Object;" 815: + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"; 816: 817: /** Bytecodes for insertion in the class definition byte[] */ 818: private static final char ACONST_NULL = 1; 819: private static final char ICONST_0 = 3; 820: private static final char BIPUSH = 16; 821: private static final char SIPUSH = 17; 822: private static final char ILOAD = 21; 823: private static final char ILOAD_0 = 26; 824: private static final char ALOAD_0 = 42; 825: private static final char ALOAD_1 = 43; 826: private static final char AALOAD = 50; 827: private static final char AASTORE = 83; 828: private static final char DUP = 89; 829: private static final char DUP_X1 = 90; 830: private static final char SWAP = 95; 831: private static final char IRETURN = 172; 832: private static final char LRETURN = 173; 833: private static final char FRETURN = 174; 834: private static final char DRETURN = 175; 835: private static final char ARETURN = 176; 836: private static final char RETURN = 177; 837: private static final char GETSTATIC = 178; 838: private static final char GETFIELD = 180; 839: private static final char INVOKEVIRTUAL = 182; 840: private static final char INVOKESPECIAL = 183; 841: private static final char INVOKEINTERFACE = 185; 842: private static final char NEW = 187; 843: private static final char ANEWARRAY