Source for java.lang.reflect.Proxy

   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