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.CPStringBuilder;
  42: 
  43: import gnu.java.lang.reflect.TypeSignature;
  44: 
  45: import java.io.Serializable;
  46: import java.security.ProtectionDomain;
  47: import java.util.Arrays;
  48: import java.util.HashMap;
  49: import java.util.HashSet;
  50: import java.util.Iterator;
  51: import java.util.Map;
  52: import java.util.Set;
  53: 
  54: /**
  55:  * This class allows you to dynamically create an instance of any (or
  56:  * even multiple) interfaces by reflection, and decide at runtime
  57:  * how that instance will behave by giving it an appropriate
  58:  * {@link InvocationHandler}.  Proxy classes serialize specially, so
  59:  * that the proxy object can be reused between VMs, without requiring
  60:  * a persistent copy of the generated class code.
  61:  *
  62:  * <h3>Creation</h3>
  63:  * To create a proxy for some interface Foo:
  64:  *
  65:  * <pre>
  66:  *   InvocationHandler handler = new MyInvocationHandler(...);
  67:  *   Class proxyClass = Proxy.getProxyClass(
  68:  *       Foo.class.getClassLoader(), new Class[] { Foo.class });
  69:  *   Foo f = (Foo) proxyClass
  70:  *       .getConstructor(new Class[] { InvocationHandler.class })
  71:  *       .newInstance(new Object[] { handler });
  72:  * </pre>
  73:  * or more simply:
  74:  * <pre>
  75:  *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  76:  *                                        new Class[] { Foo.class },
  77:  *                                        handler);
  78:  * </pre>
  79:  *
  80:  * <h3>Dynamic Proxy Classes</h3>
  81:  * A dynamic proxy class is created at runtime, and has the following
  82:  * properties:
  83:  * <ul>
  84:  *  <li>The class is <code>public</code> and <code>final</code>,
  85:  *      and is neither <code>abstract</code> nor an inner class.</li>
  86:  *  <li>The class has no canonical name (there is no formula you can use
  87:  *      to determine or generate its name), but begins with the
  88:  *      sequence "$Proxy".  Abuse this knowledge at your own peril.
  89:  *      (For now, '$' in user identifiers is legal, but it may not
  90:  *      be that way forever. You weren't using '$' in your
  91:  *      identifiers, were you?)</li>
  92:  *  <li>The class extends Proxy, and explicitly implements all the
  93:  *      interfaces specified at creation, in order (this is important
  94:  *      for determining how method invocation is resolved).  Note that
  95:  *      a proxy class implements {@link Serializable}, at least
  96:  *      implicitly, since Proxy does, but true serial behavior
  97:  *      depends on using a serializable invocation handler as well.</li>
  98:  *  <li>If at least one interface is non-public, the proxy class
  99:  *      will be in the same package.  Otherwise, the package is
 100:  *      unspecified.  This will work even if the package is sealed
 101:  *      from user-generated classes, because Proxy classes are
 102:  *      generated by a trusted source.  Meanwhile, the proxy class
 103:  *      belongs to the classloader you designated.</li>
 104:  *  <li>Reflection works as expected: {@link Class#getInterfaces()} and
 105:  *      {@link Class#getMethods()} work as they do on normal classes.</li>
 106:  *  <li>The method {@link #isProxyClass(Class)} will distinguish between
 107:  *      true proxy classes and user extensions of this class.  It only
 108:  *      returns true for classes created by {@link #getProxyClass}.</li>
 109:  *  <li>The {@link ProtectionDomain} of a proxy class is the same as for
 110:  *      bootstrap classes, such as Object or Proxy, since it is created by
 111:  *      a trusted source.  This protection domain will typically be granted
 112:  *      {@link java.security.AllPermission}. But this is not a security
 113:  *      risk, since there are adequate permissions on reflection, which is
 114:  *      the only way to create an instance of the proxy class.</li>
 115:  *  <li>The proxy class contains a single constructor, which takes as
 116:  *      its only argument an {@link InvocationHandler}.  The method
 117:  *      {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
 118:  *      is shorthand to do the necessary reflection.</li>
 119:  * </ul>
 120:  *
 121:  * <h3>Proxy Instances</h3>
 122:  * A proxy instance is an instance of a proxy class.  It has the
 123:  * following properties, many of which follow from the properties of a
 124:  * proxy class listed above:
 125:  * <ul>
 126:  *  <li>For a proxy class with Foo listed as one of its interfaces, the
 127:  *      expression <code>proxy instanceof Foo</code> will return true,
 128:  *      and the expression <code>(Foo) proxy</code> will succeed without
 129:  *      a {@link ClassCastException}.</li>
 130:  *  <li>Each proxy instance has an invocation handler, which can be
 131:  *      accessed by {@link #getInvocationHandler(Object)}.  Any call
 132:  *      to an interface method, including {@link Object#hashCode()},
 133:  *      {@link Object#equals(Object)}, or {@link Object#toString()},
 134:  *      but excluding the public final methods of Object, will be
 135:  *      encoded and passed to the {@link InvocationHandler#invoke}
 136:  *      method of this handler.</li>
 137:  * </ul>
 138:  *
 139:  * <h3>Inheritance Issues</h3>
 140:  * A proxy class may inherit a method from more than one interface.
 141:  * The order in which interfaces are listed matters, because it determines
 142:  * which reflected {@link Method} object will be passed to the invocation
 143:  * handler.  This means that the dynamically generated class cannot
 144:  * determine through which interface a method is being invoked.<p>
 145:  *
 146:  * In short, if a method is declared in Object (namely, hashCode,
 147:  * equals, or toString), then Object will be used; otherwise, the
 148:  * leftmost interface that inherits or declares a method will be used,
 149:  * even if it has a more permissive throws clause than what the proxy
 150:  * class is allowed. Thus, in the invocation handler, it is not always
 151:  * safe to assume that every class listed in the throws clause of the
 152:  * passed Method object can safely be thrown; fortunately, the Proxy
 153:  * instance is robust enough to wrap all illegal checked exceptions in
 154:  * {@link UndeclaredThrowableException}.
 155:  *
 156:  * @see InvocationHandler
 157:  * @see UndeclaredThrowableException
 158:  * @see Class
 159:  * @author Eric Blake (ebb9@email.byu.edu)
 160:  * @since 1.3
 161:  * @status updated to 1.5, except for the use of ProtectionDomain
 162:  */
 163: public class Proxy implements Serializable
 164: {
 165:   /**
 166:    * Compatible with JDK 1.3+.
 167:    */
 168:   private static final long serialVersionUID = -2222568056686623797L;
 169: 
 170:   /**
 171:    * Map of ProxyType to proxy class.
 172:    *
 173:    * @XXX This prevents proxy classes from being garbage collected.
 174:    * java.util.WeakHashSet is not appropriate, because that collects the
 175:    * keys, but we are interested in collecting the elements.
 176:    */
 177:   private static final Map proxyClasses = new HashMap();
 178: 
 179:   /**
 180:    * The invocation handler for this proxy instance.  For Proxy, this
 181:    * field is unused, but it appears here in order to be serialized in all
 182:    * proxy classes.
 183:    *
 184:    * <em>NOTE</em>: This implementation is more secure for proxy classes
 185:    * than what Sun specifies. Sun does not require h to be immutable, but
 186:    * this means you could change h after the fact by reflection.  However,
 187:    * by making h immutable, we may break non-proxy classes which extend
 188:    * Proxy.
 189:    * @serial invocation handler associated with this proxy instance
 190:    */
 191:   protected InvocationHandler h;
 192: 
 193:   /**
 194:    * Constructs a new Proxy from a subclass (usually a proxy class),
 195:    * with the specified invocation handler.
 196:    *
 197:    * <em>NOTE</em>: This throws a NullPointerException if you attempt
 198:    * to create a proxy instance with a null handler using reflection.
 199:    * This behavior is not yet specified by Sun; see Sun Bug 4487672.
 200:    *
 201:    * @param handler the invocation handler, may be null if the subclass
 202:    *        is not a proxy class
 203:    * @throws NullPointerException if handler is null and this is a proxy
 204:    *         instance
 205:    */
 206:   protected Proxy(InvocationHandler handler)
 207:   {
 208:     if (handler == null && isProxyClass(getClass()))
 209:       throw new NullPointerException("invalid handler");
 210:     h = handler;
 211:   }
 212: 
 213:   /**
 214:    * Returns the proxy {@link Class} for the given ClassLoader and array
 215:    * of interfaces, dynamically generating it if necessary.
 216:    *
 217:    * <p>There are several restrictions on this method, the violation of
 218:    * which will result in an IllegalArgumentException or
 219:    * NullPointerException:</p>
 220:    *
 221:    * <ul>
 222:    * <li>All objects in `interfaces' must represent distinct interfaces.
 223:    *     Classes, primitive types, null, and duplicates are forbidden.</li>
 224:    * <li>The interfaces must be visible in the specified ClassLoader.
 225:    *     In other words, for each interface i:
 226:    *     <code>Class.forName(i.getName(), false, loader) == i</code>
 227:    *     must be true.</li>
 228:    * <li>All non-public interfaces (if any) must reside in the same
 229:    *     package, or the proxy class would be non-instantiable.  If
 230:    *     there are no non-public interfaces, the package of the proxy
 231:    *     class is unspecified.</li>
 232:    * <li>All interfaces must be compatible - if two declare a method
 233:    *     with the same name and parameters, the return type must be
 234:    *     the same and the throws clause of the proxy class will be
 235:    *     the maximal subset of subclasses of the throws clauses for
 236:    *     each method that is overridden.</li>
 237:    * <li>VM constraints limit the number of interfaces a proxy class
 238:    *     may directly implement (however, the indirect inheritance
 239:    *     of {@link Serializable} does not count against this limit).
 240:    *     Even though most VMs can theoretically have 65535
 241:    *     superinterfaces for a class, the actual limit is smaller
 242:    *     because a class's constant pool is limited to 65535 entries,
 243:    *     and not all entries can be interfaces.</li>
 244:    * </ul>
 245:    *
 246:    * <p>Note that different orders of interfaces produce distinct classes.</p>
 247:    *
 248:    * @param loader the class loader to define the proxy class in; null
 249:    *        implies the bootstrap class loader
 250:    * @param interfaces the array of interfaces the proxy class implements,
 251:    *        may be empty, but not null
 252:    * @return the Class object of the proxy class
 253:    * @throws IllegalArgumentException if the constraints above were
 254:    *         violated, except for problems with null
 255:    * @throws NullPointerException if `interfaces' is null or contains
 256:    *         a null entry
 257:    */
 258:   // synchronized so that we aren't trying to build the same class
 259:   // simultaneously in two threads
 260:   public static synchronized Class<?> getProxyClass(ClassLoader loader,
 261:                                                     Class<?>... interfaces)
 262:   {
 263:     interfaces = (Class[]) interfaces.clone();
 264:     ProxyType pt = new ProxyType(loader, interfaces);
 265:     Class clazz = (Class) proxyClasses.get(pt);
 266:     if (clazz == null)
 267:       {
 268:         if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
 269:           clazz = VMProxy.getProxyClass(loader, interfaces);
 270:         else
 271:           {
 272:             ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
 273:                               ? VMProxy.getProxyData(loader, interfaces)
 274:                               : ProxyData.getProxyData(pt));
 275: 
 276:             clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
 277:                      ? VMProxy.generateProxyClass(loader, data)
 278:                      : new ClassFactory(data).generate(loader));
 279:           }
 280: 
 281:         Object check = proxyClasses.put(pt, clazz);
 282:         // assert check == null && clazz != null;
 283:         if (check != null || clazz == null)
 284:           throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
 285:       }
 286:     return clazz;
 287:   }
 288: 
 289:   /**
 290:    * Combines several methods into one.  This is equivalent to:
 291:    * <pre>
 292:    *   Proxy.getProxyClass(loader, interfaces)
 293:    *       .getConstructor(new Class[] {InvocationHandler.class})
 294:    *       .newInstance(new Object[] {handler});
 295:    * </pre>
 296:    * except that it will not fail with the normal problems caused
 297:    * by reflection.  It can still fail for the same reasons documented
 298:    * in getProxyClass, or if handler is null.
 299:    *
 300:    * @param loader the class loader to define the proxy class in; null
 301:    *        implies the bootstrap class loader
 302:    * @param interfaces the array of interfaces the proxy class implements,
 303:    *        may be empty, but not null
 304:    * @param handler the invocation handler, may not be null
 305:    * @return a proxy instance implementing the specified interfaces
 306:    * @throws IllegalArgumentException if the constraints for getProxyClass
 307:    *         were violated, except for problems with null
 308:    * @throws NullPointerException if `interfaces' is null or contains
 309:    *         a null entry, or if handler is null
 310:    * @see #getProxyClass(ClassLoader, Class[])
 311:    * @see Class#getConstructor(Class[])
 312:    * @see Constructor#newInstance(Object[])
 313:    */
 314:   public static Object newProxyInstance(ClassLoader loader,
 315:                                         Class<?>[] interfaces,
 316:                                         InvocationHandler handler)
 317:   {
 318:     try
 319:       {
 320:         // getProxyClass() and Proxy() throw the necessary exceptions
 321:         return getProxyClass(loader, interfaces)
 322:           .getConstructor(new Class[] {InvocationHandler.class})
 323:           .newInstance(new Object[] {handler});
 324:       }
 325:     catch (RuntimeException e)
 326:       {
 327:         // Let IllegalArgumentException, NullPointerException escape.
 328:         // assert e instanceof IllegalArgumentException
 329:         //   || e instanceof NullPointerException;
 330:         throw e;
 331:       }
 332:     catch (InvocationTargetException e)
 333:       {
 334:         // Let wrapped NullPointerException escape.
 335:         // assert e.getTargetException() instanceof NullPointerException
 336:         throw (NullPointerException) e.getCause();
 337:       }
 338:     catch (Exception e)
 339:       {
 340:         // Covers InstantiationException, IllegalAccessException,
 341:         // NoSuchMethodException, none of which should be generated
 342:         // if the proxy class was generated correctly.
 343:         // assert false;
 344:         throw (Error) new InternalError("Unexpected: " + e).initCause(e);
 345:       }
 346:   }
 347: 
 348:   /**
 349:    * Returns true if and only if the Class object is a dynamically created
 350:    * proxy class (created by <code>getProxyClass</code> or by the
 351:    * syntactic sugar of <code>newProxyInstance</code>).
 352:    *
 353:    * <p>This check is secure (in other words, it is not simply
 354:    * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
 355:    * be spoofed by non-proxy classes that extend Proxy.
 356:    *
 357:    * @param clazz the class to check, must not be null
 358:    * @return true if the class represents a proxy class
 359:    * @throws NullPointerException if clazz is null
 360:    */
 361:   // This is synchronized on the off chance that another thread is
 362:   // trying to add a class to the map at the same time we read it.
 363:   public static synchronized boolean isProxyClass(Class<?> clazz)
 364:   {
 365:     if (! Proxy.class.isAssignableFrom(clazz))
 366:       return false;
 367:     // This is a linear search, even though we could do an O(1) search
 368:     // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
 369:     return proxyClasses.containsValue(clazz);
 370:   }
 371: 
 372:   /**
 373:    * Returns the invocation handler for the given proxy instance.<p>
 374:    *
 375:    * <em>NOTE</em>: We guarantee a non-null result if successful,
 376:    * but Sun allows the creation of a proxy instance with a null
 377:    * handler.  See the comments for {@link #Proxy(InvocationHandler)}.
 378:    *
 379:    * @param proxy the proxy instance, must not be null
 380:    * @return the invocation handler, guaranteed non-null.
 381:    * @throws IllegalArgumentException if
 382:    *         <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
 383:    * @throws NullPointerException if proxy is null
 384:    */
 385:   public static InvocationHandler getInvocationHandler(Object proxy)
 386:   {
 387:     if (! isProxyClass(proxy.getClass()))
 388:       throw new IllegalArgumentException("not a proxy instance");
 389:     return ((Proxy) proxy).h;
 390:   }
 391: 
 392:   /**
 393:    * Helper class for mapping unique ClassLoader and interface combinations
 394:    * to proxy classes.
 395:    *
 396:    * @author Eric Blake (ebb9@email.byu.edu)
 397:    */
 398:   private static final class ProxyType
 399:   {
 400:     /**
 401:      * Store the class loader (may be null)
 402:      */
 403:     final ClassLoader loader;
 404: 
 405:     /**
 406:      * Store the interfaces (never null, all elements are interfaces)
 407:      */
 408:     final Class[] interfaces;
 409: 
 410:     /**
 411:      * Construct the helper object.
 412:      *
 413:      * @param loader the class loader to define the proxy class in; null
 414:      *        implies the bootstrap class loader
 415:      * @param interfaces an array of interfaces
 416:      */
 417:     ProxyType(ClassLoader loader, Class[] interfaces)
 418:     {
 419:       this.loader = loader;
 420:       this.interfaces = interfaces;
 421:     }
 422: 
 423:     /**
 424:      * Calculates the hash code.
 425:      *
 426:      * @return a combination of the classloader and interfaces hashcodes.
 427:      */
 428:     public int hashCode()
 429:     {
 430:       int hash = loader == null ? 0 : loader.hashCode();
 431:       for (int i = 0; i < interfaces.length; i++)
 432:         hash = hash * 31 + interfaces[i].hashCode();
 433:       return hash;
 434:     }
 435: 
 436:     /**
 437:      * Calculates equality.
 438:      *
 439:      * @param other object to compare to
 440:      * @return true if it is a ProxyType with same data
 441:      */
 442:     public boolean equals(Object other)
 443:     {
 444:       ProxyType pt = (ProxyType) other;
 445:       if (loader != pt.loader || interfaces.length != pt.interfaces.length)
 446:         return false;
 447:       for (int i = 0; i < interfaces.length; i++)
 448:         if (interfaces[i] != pt.interfaces[i])
 449:           return false;
 450:       return true;
 451:     }
 452:   } // class ProxyType
 453: 
 454:   /**
 455:    * Helper class which allows hashing of a method name and signature
 456:    * without worrying about return type, declaring class, or throws clause,
 457:    * and which reduces the maximally common throws clause between two methods
 458:    *
 459:    * @author Eric Blake (ebb9@email.byu.edu)
 460:    */
 461:   private static final class ProxySignature
 462:   {
 463:     /**
 464:      * The core signatures which all Proxy instances handle.
 465:      */
 466:     static final HashMap coreMethods = new HashMap();
 467:     static
 468:     {
 469:       try
 470:         {
 471:           ProxySignature sig
 472:             = new ProxySignature(Object.class
 473:                                  .getMethod("equals",
 474:                                             new Class[] {Object.class}));
 475:           coreMethods.put(sig, sig);
 476:           sig = new ProxySignature(Object.class.getMethod("hashCode"));
 477:           coreMethods.put(sig, sig);
 478:           sig = new ProxySignature(Object.class.getMethod("toString"));
 479:           coreMethods.put(sig, sig);
 480:         }
 481:       catch (Exception e)
 482:         {
 483:           // assert false;
 484:           throw (Error) new InternalError("Unexpected: " + e).initCause(e);
 485:         }
 486:     }
 487: 
 488:     /**
 489:      * The underlying Method object, never null
 490:      */
 491:     final Method method;
 492: 
 493:     /**
 494:      * The set of compatible thrown exceptions, may be empty
 495:      */
 496:     final Set exceptions = new HashSet();
 497: 
 498:     /**
 499:      * Construct a signature
 500:      *
 501:      * @param method the Method this signature is based on, never null
 502:      */
 503:     ProxySignature(Method method)
 504:     {
 505:       this.method = method;
 506:       Class[] exc = method.getExceptionTypes();
 507:       int i = exc.length;
 508:       while (--i >= 0)
 509:         {
 510:           // discard unchecked exceptions
 511:           if (Error.class.isAssignableFrom(exc[i])
 512:               || RuntimeException.class.isAssignableFrom(exc[i]))
 513:             continue;
 514:           exceptions.add(exc[i]);
 515:         }
 516:     }
 517: 
 518:     /**
 519:      * Given a method, make sure it's return type is identical
 520:      * to this, and adjust this signature's throws clause appropriately
 521:      *
 522:      * @param other the signature to merge in
 523:      * @throws IllegalArgumentException if the return types conflict
 524:      */
 525:     void checkCompatibility(ProxySignature other)
 526:     {
 527:       if (method.getReturnType() != other.method.getReturnType())
 528:         throw new IllegalArgumentException("incompatible return types: "
 529:                                            + method + ", " + other.method);
 530: 
 531:       // if you can think of a more efficient way than this O(n^2) search,
 532:       // implement it!
 533:       int size1 = exceptions.size();
 534:       int size2 = other.exceptions.size();
 535:       boolean[] valid1 = new boolean[size1];
 536:       boolean[] valid2 = new boolean[size2];
 537:       Iterator itr = exceptions.iterator();
 538:       int pos = size1;
 539:       while (--pos >= 0)
 540:         {
 541:           Class c1 = (Class) itr.next();
 542:           Iterator itr2 = other.exceptions.iterator();
 543:           int pos2 = size2;
 544:           while (--pos2 >= 0)
 545:             {
 546:               Class c2 = (Class) itr2.next();
 547:               if (c2.isAssignableFrom(c1))
 548:                 valid1[pos] = true;
 549:               if (c1.isAssignableFrom(c2))
 550:                 valid2[pos2] = true;
 551:             }
 552:         }
 553:       pos = size1;
 554:       itr = exceptions.iterator();
 555:       while (--pos >= 0)
 556:         {
 557:           itr.next();
 558:           if (! valid1[pos])
 559:             itr.remove();
 560:         }
 561:       pos = size2;
 562:       itr = other.exceptions.iterator();
 563:       while (--pos >= 0)
 564:         {
 565:           itr.next();
 566:           if (! valid2[pos])
 567:             itr.remove();
 568:         }
 569:       exceptions.addAll(other.exceptions);
 570:     }
 571: 
 572:     /**
 573:      * Calculates the hash code.
 574:      *
 575:      * @return a combination of name and parameter types
 576:      */
 577:     public int hashCode()
 578:     {
 579:       int hash = method.getName().hashCode();
 580:       Class[] types = method.getParameterTypes();
 581:       for (int i = 0; i < types.length; i++)
 582:         hash = hash * 31 + types[i].hashCode();
 583:       return hash;
 584:     }
 585: 
 586:     /**
 587:      * Calculates equality.
 588:      *
 589:      * @param other object to compare to
 590:      * @return true if it is a ProxySignature with same data
 591:      */
 592:     public boolean equals(Object other)
 593:     {
 594:       ProxySignature ps = (ProxySignature) other;
 595:       Class[] types1 = method.getParameterTypes();
 596:       Class[] types2 = ps.method.getParameterTypes();
 597:       if (! method.getName().equals(ps.method.getName())
 598:           || types1.length != types2.length)
 599:         return false;
 600:       int i = types1.length;
 601:       while (--i >= 0)
 602:         if (types1[i] != types2[i])
 603:           return false;
 604:       return true;
 605:     }
 606:   } // class ProxySignature
 607: 
 608:   /**
 609:    * A flat representation of all data needed to generate bytecode/instantiate
 610:    * a proxy class.  This is basically a struct.
 611:    *
 612:    * @author Eric Blake (ebb9@email.byu.edu)
 613:    */
 614:   static final class ProxyData
 615:   {
 616:     /**
 617:      * The package this class is in <b>including the trailing dot</b>
 618:      * or an empty string for the unnamed (aka default) package.
 619:      */
 620:     String pack = "";
 621: 
 622:     /**
 623:      * The interfaces this class implements.  Non-null, but possibly empty.
 624:      */
 625:     Class[] interfaces;
 626: 
 627:     /**
 628:      * The Method objects this class must pass as the second argument to
 629:      * invoke (also useful for determining what methods this class has).
 630:      * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
 631:      * and Object.toString).
 632:      */
 633:     Method[] methods;
 634: 
 635:     /**
 636:      * The exceptions that do not need to be wrapped in
 637:      * UndeclaredThrowableException. exceptions[i] is the same as, or a
 638:      * subset of subclasses, of methods[i].getExceptionTypes(), depending on
 639:      * compatible throws clauses with multiple inheritance. It is unspecified
 640:      * if these lists include or exclude subclasses of Error and
 641:      * RuntimeException, but excluding them is harmless and generates a
 642:      * smaller class.
 643:      */
 644:     Class[][] exceptions;
 645: 
 646:     /**
 647:      * For unique id's
 648:      */
 649:     private static int count;
 650: 
 651:     /**
 652:      * The id of this proxy class
 653:      */
 654:     final int id = count++;
 655: 
 656:     /**
 657:      * Construct a ProxyData with uninitialized data members.
 658:      */
 659:     ProxyData()
 660:     {
 661:     }
 662: 
 663:     /**
 664:      * Return the name of a package (including the trailing dot)
 665:      * given the name of a class.
 666:      * Returns an empty string if no package.  We use this in preference to
 667:      * using Class.getPackage() to avoid problems with ClassLoaders
 668:      * that don't set the package.
 669:      */
 670:     private static String getPackage(Class k)
 671:     {
 672:       String name = k.getName();
 673:       int idx = name.lastIndexOf('.');
 674:       return name.substring(0, idx + 1);
 675:     }
 676: 
 677:     /**
 678:      * Verifies that the arguments are legal, and sets up remaining data
 679:      * This should only be called when a class must be generated, as
 680:      * it is expensive.
 681:      *
 682:      * @param pt the ProxyType to convert to ProxyData
 683:      * @return the flattened, verified ProxyData structure for use in
 684:      *         class generation
 685:      * @throws IllegalArgumentException if `interfaces' contains
 686:      *         non-interfaces or incompatible combinations, and verify is true
 687:      * @throws NullPointerException if interfaces is null or contains null
 688:      */
 689:     static ProxyData getProxyData(ProxyType pt)
 690:     {
 691:       Map method_set = (Map) ProxySignature.coreMethods.clone();
 692:       boolean in_package = false; // true if we encounter non-public interface
 693: 
 694:       ProxyData data = new ProxyData();
 695:       data.interfaces = pt.interfaces;
 696: 
 697:       // if interfaces is too large, we croak later on when the constant
 698:       // pool overflows
 699:       int i = data.interfaces.length;
 700:       while (--i >= 0)
 701:         {
 702:           Class inter = data.interfaces[i];
 703:           if (! inter.isInterface())
 704:             throw new IllegalArgumentException("not an interface: " + inter);
 705:           try
 706:             {
 707:               if (Class.forName(inter.getName(), false, pt.loader) != inter)
 708:                 throw new IllegalArgumentException("not accessible in "
 709:                                                    + "classloader: " + inter);
 710:             }
 711:           catch (ClassNotFoundException e)
 712:             {
 713:               throw new IllegalArgumentException("not accessible in "
 714:                                                  + "classloader: " + inter);
 715:             }
 716:           if (! Modifier.isPublic(inter.getModifiers()))
 717:             if (in_package)
 718:               {
 719:                 String p = getPackage(inter);
 720:                 if (! data.pack.equals(p))
 721:                   throw new IllegalArgumentException("non-public interfaces "
 722:                                                      + "from different "
 723:                                                      + "packages");
 724:               }
 725:             else
 726:               {
 727:                 in_package = true;
 728:                 data.pack = getPackage(inter);
 729:               }
 730:           for (int j = i-1; j >= 0; j--)
 731:             if (data.interfaces[j] == inter)
 732:               throw new IllegalArgumentException("duplicate interface: "
 733:                                                  + inter);
 734:           Method[] methods = inter.getMethods();
 735:           int j = methods.length;
 736:           while (--j >= 0)
 737:             {
 738:               if (isCoreObjectMethod(methods[j]))
 739:                 {
 740:                   // In the case of an attempt to redefine a public non-final
 741:                   // method of Object, we must skip it
 742:                   continue;
 743:                 }
 744:               ProxySignature sig = new ProxySignature(methods[j]);
 745:               ProxySignature old = (ProxySignature) method_set.put(sig, sig);
 746:               if (old != null)
 747:                 sig.checkCompatibility(old);
 748:             }
 749:         }
 750: 
 751:       i = method_set.size();
 752:       data.methods = new Method[i];
 753:       data.exceptions = new Class[i][];
 754:       Iterator itr = method_set.values().iterator();
 755:       while (--i >= 0)
 756:         {
 757:           ProxySignature sig = (ProxySignature) itr.next();
 758:           data.methods[i] = sig.method;
 759:           data.exceptions[i] = (Class[]) sig.exceptions
 760:             .toArray(new Class[sig.exceptions.size()]);
 761:         }
 762:       return data;
 763:     }
 764: 
 765:     /**
 766:      * Checks whether the method is similar to a public non-final method of
 767:      * Object or not (i.e. with the same name and parameter types). Note that we
 768:      * can't rely, directly or indirectly (via Collection.contains) on
 769:      * Method.equals as it would also check the declaring class, what we do not
 770:      * want. We only want to check that the given method have the same signature
 771:      * as a core method (same name and parameter types)
 772:      *
 773:      * @param method the method to check
 774:      * @return whether the method has the same name and parameter types as
 775:      *         Object.equals, Object.hashCode or Object.toString
 776:      * @see java.lang.Object#equals(Object)
 777:      * @see java.lang.Object#hashCode()
 778:      * @see java.lang.Object#toString()
 779:      */
 780:     private static boolean isCoreObjectMethod(Method method)
 781:     {
 782:       String methodName = method.getName();
 783:       if (methodName.equals("equals"))
 784:         {
 785:           return Arrays.equals(method.getParameterTypes(),
 786:                                new Class[] { Object.class });
 787:         }
 788:       if (methodName.equals("hashCode"))
 789:         {
 790:           return method.getParameterTypes().length == 0;
 791:         }
 792:       if (methodName.equals("toString"))
 793:         {
 794:           return method.getParameterTypes().length == 0;
 795:         }
 796:       return false;
 797:     }
 798: 
 799:   } // class ProxyData
 800: 
 801:   /**
 802:    * Does all the work of building a class. By making this a nested class,
 803:    * this code is not loaded in memory if the VM has a native
 804:    * implementation instead.
 805:    *
 806:    * @author Eric Blake (ebb9@email.byu.edu)
 807:    */
 808:   private static final class ClassFactory
 809:   {
 810:     /** Constants for assisting the compilation */
 811:     private static final byte FIELD = 1;
 812:     private static final byte METHOD = 2;
 813:     private static final byte INTERFACE = 3;
 814:     private static final String CTOR_SIG
 815:       = "(Ljava/lang/reflect/InvocationHandler;)V";
 816:     private static final String INVOKE_SIG = "(Ljava/lang/Object;"
 817:       + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
 818: 
 819:     /** Bytecodes for insertion in the class definition byte[] */
 820:     private static final char ACONST_NULL = 1;
 821:     private static final char ICONST_0 = 3;
 822:     private static final char BIPUSH = 16;
 823:     private static final char SIPUSH = 17;
 824:     private static final char ILOAD = 21;
 825:     private static final char ILOAD_0 = 26;
 826:     private static final char ALOAD_0 = 42;
 827:     private static final char ALOAD_1 = 43;
 828:     private static final char AALOAD = 50;
 829:     private static final char AASTORE = 83;
 830:     private static final char DUP = 89;
 831:     private static final char DUP_X1 = 90;
 832:     private static final char SWAP = 95;
 833:     private static final char IRETURN = 172;
 834:     private static final char LRETURN = 173;
 835:     private static final char FRETURN = 174;
 836:     private static final char DRETURN = 175;
 837:     private static final char ARETURN = 176;
 838:     private static final char RETURN = 177;
 839:     private static final char GETSTATIC = 178;
 840:     private static final char GETFIELD = 180;
 841:     private static final char INVOKEVIRTUAL = 182;
 842:     private static final char INVOKESPECIAL = 183;
 843:     private static final char INVOKEINTERFACE = 185;
 844:     private static final char NEW = 187;
 845:     private static final char ANEWARRAY = 189;
 846:     private static final char ATHROW = 191;
 847:     private static final char CHECKCAST = 192;
 848: 
 849:     // Implementation note: we use StringBuffers to hold the byte data, since
 850:     // they automatically grow.  However, we only use the low 8 bits of
 851:     // every char in the array, so we are using twice the necessary memory
 852:     // for the ease StringBuffer provides.
 853: 
 854:     /** The constant pool. */
 855:     private final StringBuffer pool = new StringBuffer();
 856:     /** The rest of the class data. */
 857:     private final StringBuffer stream = new StringBuffer();
 858: 
 859:     /** Map of strings to byte sequences, to minimize size of pool. */
 860:     private final Map poolEntries = new HashMap();
 861: 
 862:     /** The VM name of this proxy class. */
 863:     private final String qualName;
 864: 
 865:     /**
 866:      * The Method objects the proxy class refers to when calling the
 867:      * invocation handler.
 868:      */
 869:     private final Method[] methods;
 870: 
 871:     /**
 872:      * Initializes the buffers with the bytecode contents for a proxy class.
 873:      *
 874:      * @param data the remainder of the class data
 875:      * @throws IllegalArgumentException if anything else goes wrong this
 876:      *         late in the game; as far as I can tell, this will only happen
 877:      *         if the constant pool overflows, which is possible even when
 878:      *         the user doesn't exceed the 65535 interface limit
 879:      */
 880:     ClassFactory(ProxyData data)
 881:     {
 882:       methods = data.methods;
 883: 
 884:       // magic = 0xcafebabe
 885:       // minor_version = 0
 886:       // major_version = 46
 887:       // constant_pool_count: place-holder for now
 888:       pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
 889:       // constant_pool[], filled in as we go
 890: 
 891:       // access_flags
 892:       putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
 893:       // this_class
 894:       qualName = (data.pack + "$Proxy" + data.id);
 895:       putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
 896:       // super_class
 897:       putU2(classInfo("java/lang/reflect/Proxy"));
 898: 
 899:       // interfaces_count
 900:       putU2(data.interfaces.length);
 901:       // interfaces[]
 902:       for (int i = 0; i < data.interfaces.length; i++)
 903:         putU2(classInfo(data.interfaces[i]));
 904: 
 905:       // Recall that Proxy classes serialize specially, so we do not need
 906:       // to worry about a <clinit> method for this field.  Instead, we
 907:       // just assign it by reflection after the class is successfully loaded.
 908:       // fields_count - private static Method[] m;
 909:       putU2(1);
 910:       // fields[]
 911:       // m.access_flags
 912:       putU2(Modifier.PRIVATE | Modifier.STATIC);
 913:       // m.name_index
 914:       putU2(utf8Info("m"));
 915:       // m.descriptor_index
 916:       putU2(utf8Info("[Ljava/lang/reflect/Method;"));
 917:       // m.attributes_count
 918:       putU2(0);
 919:       // m.attributes[]
 920: 
 921:       // methods_count - # handler methods, plus <init>
 922:       putU2(methods.length + 1);
 923:       // methods[]
 924:       // <init>.access_flags
 925:       putU2(Modifier.PUBLIC);
 926:       // <init>.name_index
 927:       putU2(utf8Info("<init>"));
 928:       // <init>.descriptor_index
 929:       putU2(utf8Info(CTOR_SIG));
 930:       // <init>.attributes_count - only Code is needed
 931:       putU2(1);
 932:       // <init>.Code.attribute_name_index
 933:       putU2(utf8Info("Code"));
 934:       // <init>.Code.attribute_length = 18
 935:       // <init>.Code.info:
 936:       //   $Proxynn(InvocationHandler h) { super(h); }
 937:       // <init>.Code.max_stack = 2
 938:       // <init>.Code.max_locals = 2
 939:       // <init>.Code.code_length = 6
 940:       // <init>.Code.code[]
 941:       stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
 942:                     + INVOKESPECIAL);
 943:       putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
 944:       // <init>.Code.exception_table_length = 0
 945:       // <init>.Code.exception_table[]
 946:       // <init>.Code.attributes_count = 0
 947:       // <init>.Code.attributes[]
 948:       stream.append(RETURN + "\0\0\0\0");
 949: 
 950:       for (int i = methods.length - 1; i >= 0; i--)
 951:         emitMethod(i, data.exceptions[i]);
 952: 
 953:       // attributes_count
 954:       putU2(0);
 955:       // attributes[] - empty; omit SourceFile attribute
 956:       // XXX should we mark this with a Synthetic attribute?
 957:     }
 958: 
 959:     /**
 960:      * Produce the bytecode for a single method.
 961:      *
 962:      * @param i the index of the method we are building
 963:      * @param e the exceptions possible for the method
 964:      */
 965:     private void emitMethod(int i, Class[] e)
 966:     {
 967:       // First, we precalculate the method length and other information.
 968: 
 969:       Method m = methods[i];
 970:       Class[] paramtypes = m.getParameterTypes();
 971:       int wrap_overhead = 0; // max words taken by wrapped primitive
 972:       int param_count = 1; // 1 for this
 973:       int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
 974:       // aaload, const/aconst_null, invokeinterface
 975:       if (i > 5)
 976:         {
 977:           if (i > Byte.MAX_VALUE)
 978:             code_length += 2; // sipush
 979:           else
 980:             code_length++; // bipush
 981:         }
 982:       if (paramtypes.length > 0)
 983:         {
 984:           code_length += 3; // anewarray
 985:           if (paramtypes.length > Byte.MAX_VALUE)
 986:             code_length += 2; // sipush
 987:           else if (paramtypes.length > 5)
 988:             code_length++; // bipush
 989:           for (int j = 0; j < paramtypes.length; j++)
 990:             {
 991:               code_length += 4; // dup, const, load, store
 992:               Class type = paramtypes[j];
 993:               if (j > 5)
 994:                 {
 995:                   if (j > Byte.MAX_VALUE)
 996:                     code_length += 2; // sipush
 997:                   else
 998:                     code_length++; // bipush
 999:                 }
1000:               if (param_count >= 4)
1001:                 code_length++; // 2-byte load
1002:               param_count++;
1003:               if (type.isPrimitive())
1004:                 {
1005:                   code_length += 7; // new, dup, invokespecial
1006:                   if (type == long.class || type == double.class)
1007:                     {
1008:                       wrap_overhead = 3;
1009:                       param_count++;
1010:                     }
1011:                   else if (wrap_overhead < 2)
1012:                     wrap_overhead = 2;
1013:                 }
1014:             }
1015:         }
1016:       int end_pc = code_length;
1017:       Class ret_type = m.getReturnType();
1018:       if (ret_type == void.class)
1019:         code_length++; // return
1020:       else if (ret_type.isPrimitive())
1021:         code_length += 7; // cast, invokevirtual, return
1022:       else
1023:         code_length += 4; // cast, return
1024:       int exception_count = 0;
1025:       boolean throws_throwable = false;
1026:       for (int j = 0; j < e.length; j++)
1027:         if (e[j] == Throwable.class)
1028:           {
1029:             throws_throwable = true;
1030:             break;
1031:           }
1032:       if (! throws_throwable)
1033:         {
1034:           exception_count = e.length + 3; // Throwable, Error, RuntimeException
1035:           code_length += 9; // new, dup_x1, swap, invokespecial, athrow
1036:         }
1037:       int handler_pc = code_length - 1;
1038:       CPStringBuilder signature = new CPStringBuilder("(");
1039:       for (int j = 0; j < paramtypes.length; j++)
1040:         signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
1041:       signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
1042: 
1043:       // Now we have enough information to emit the method.
1044: 
1045:       // handler.access_flags
1046:       putU2(Modifier.PUBLIC | Modifier.FINAL);
1047:       // handler.name_index
1048:       putU2(utf8Info(m.getName()));
1049:       // handler.descriptor_index
1050:       putU2(utf8Info(signature.toString()));
1051:       // handler.attributes_count - Code is necessary, Exceptions possible
1052:       putU2(e.length > 0 ? 2 : 1);
1053: 
1054:       // handler.Code.info:
1055:       //   type name(args) {
1056:       //     try {
1057:       //       return (type) h.invoke(this, methods[i], new Object[] {args});
1058:       //     } catch (<declared Exceptions> e) {
1059:       //       throw e;
1060:       //     } catch (Throwable t) {
1061:       //       throw new UndeclaredThrowableException(t);
1062:       //     }
1063:       //   }
1064:       // Special cases:
1065:       //  if arg_n is primitive, wrap it
1066:       //  if method throws Throwable, try-catch is not needed
1067:       //  if method returns void, return statement not needed
1068:       //  if method returns primitive, unwrap it
1069:       //  save space by sharing code for all the declared handlers
1070: 
1071:       // handler.Code.attribute_name_index
1072:       putU2(utf8Info("Code"));
1073:       // handler.Code.attribute_length
1074:       putU4(12 + code_length + 8 * exception_count);
1075:       // handler.Code.max_stack
1076:       putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
1077:       // handler.Code.max_locals
1078:       putU2(param_count);
1079:       // handler.Code.code_length
1080:       putU4(code_length);
1081:       // handler.Code.code[]
1082:       putU1(ALOAD_0);
1083:       putU1(GETFIELD);
1084:       putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
1085:                     "Ljava/lang/reflect/InvocationHandler;"));
1086:       putU1(ALOAD_0);
1087:       putU1(GETSTATIC);
1088:       putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
1089:                     "m", "[Ljava/lang/reflect/Method;"));
1090:       putConst(i);
1091:       putU1(AALOAD);
1092:       if (paramtypes.length > 0)
1093:         {
1094:           putConst(paramtypes.length);
1095:           putU1(ANEWARRAY);
1096:           putU2(classInfo("java/lang/Object"));
1097:           param_count = 1;
1098:           for (int j = 0; j < paramtypes.length; j++, param_count++)
1099:             {
1100:               putU1(DUP);
1101:               putConst(j);
1102:               if (paramtypes[j].isPrimitive())
1103:                 {
1104:                   putU1(NEW);
1105:                   putU2(classInfo(wrapper(paramtypes[j])));
1106:                   putU1(DUP);
1107:                 }
1108:               putLoad(param_count, paramtypes[j]);
1109:               if (paramtypes[j].isPrimitive())
1110:                 {
1111:                   putU1(INVOKESPECIAL);
1112:                   putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
1113:                                 '(' + (TypeSignature
1114:                                        .getEncodingOfClass(paramtypes[j])
1115:                                        + ")V")));
1116:                   if (paramtypes[j] == long.class
1117:                       || paramtypes[j] == double.class)
1118:                     param_count++;
1119:                 }
1120:               putU1(AASTORE);
1121:             }
1122:         }
1123:       else
1124:         putU1(ACONST_NULL);
1125:       putU1(INVOKEINTERFACE);
1126:       putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
1127:                     "invoke", INVOKE_SIG));
1128:       putU1(4); // InvocationHandler, this, Method, Object[]
1129:       putU1(0);
1130:       if (ret_type == void.class)
1131:         putU1(RETURN);
1132:       else if (ret_type.isPrimitive())
1133:         {
1134:           putU1(CHECKCAST);
1135:           putU2(classInfo(wrapper(ret_type)));
1136:           putU1(INVOKEVIRTUAL);
1137:           putU2(refInfo(METHOD, wrapper(ret_type),
1138:                         ret_type.getName() + "Value",
1139:                         "()" + TypeSignature.getEncodingOfClass(ret_type)));
1140:           if (ret_type == long.class)
1141:             putU1(LRETURN);
1142:           else if (ret_type == float.class)
1143:             putU1(FRETURN);
1144:           else if (ret_type == double.class)
1145:             putU1(DRETURN);
1146:           else
1147:             putU1(IRETURN);
1148:         }
1149:       else
1150:         {
1151:           putU1(CHECKCAST);
1152:           putU2(classInfo(ret_type));
1153:           putU1(ARETURN);
1154:         }
1155:       if (! throws_throwable)
1156:         {
1157:           putU1(NEW);
1158:           putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
1159:           putU1(DUP_X1);
1160:           putU1(SWAP);
1161:           putU1(INVOKESPECIAL);
1162:           putU2(refInfo(METHOD,
1163:                         "java/lang/reflect/UndeclaredThrowableException",
1164:                         "<init>", "(Ljava/lang/Throwable;)V"));
1165:           putU1(ATHROW);
1166:         }
1167: 
1168:       // handler.Code.exception_table_length
1169:       putU2(exception_count);
1170:       // handler.Code.exception_table[]
1171:       if (! throws_throwable)
1172:         {
1173:           // handler.Code.exception_table.start_pc
1174:           putU2(0);
1175:           // handler.Code.exception_table.end_pc
1176:           putU2(end_pc);
1177:           // handler.Code.exception_table.handler_pc
1178:           putU2(handler_pc);
1179:           // handler.Code.exception_table.catch_type
1180:           putU2(classInfo("java/lang/Error"));
1181:           // handler.Code.exception_table.start_pc
1182:           putU2(0);
1183:           // handler.Code.exception_table.end_pc
1184:           putU2(end_pc);
1185:           // handler.Code.exception_table.handler_pc
1186:           putU2(handler_pc);
1187:           // handler.Code.exception_table.catch_type
1188:           putU2(classInfo("java/lang/RuntimeException"));
1189:           for (int j = 0; j < e.length; j++)
1190:             {
1191:               // handler.Code.exception_table.start_pc
1192:               putU2(0);
1193:               // handler.Code.exception_table.end_pc
1194:               putU2(end_pc);
1195:               // handler.Code.exception_table.handler_pc
1196:               putU2(handler_pc);
1197:               // handler.Code.exception_table.catch_type
1198:               putU2(classInfo(e[j]));
1199:             }
1200:           // handler.Code.exception_table.start_pc
1201:           putU2(0);
1202:           // handler.Code.exception_table.end_pc
1203:           putU2(end_pc);
1204:           // handler.Code.exception_table.handler_pc -
1205:           //   -8 for undeclared handler, which falls thru to normal one
1206:           putU2(handler_pc - 8);
1207:           // handler.Code.exception_table.catch_type
1208:           putU2(0);
1209:         }
1210:       // handler.Code.attributes_count
1211:       putU2(0);
1212:       // handler.Code.attributes[]
1213: 
1214:       if (e.length > 0)
1215:         {
1216:           // handler.Exceptions.attribute_name_index
1217:           putU2(utf8Info("Exceptions"));
1218:           // handler.Exceptions.attribute_length
1219:           putU4(2 * e.length + 2);
1220:           // handler.Exceptions.number_of_exceptions
1221:           putU2(e.length);
1222:           // handler.Exceptions.exception_index_table[]
1223:           for (int j = 0; j < e.length; j++)
1224:             putU2(classInfo(e[j]));
1225:         }
1226:     }
1227: 
1228:     /**
1229:      * Creates the Class object that corresponds to the bytecode buffers
1230:      * built when this object was constructed.
1231:      *
1232:      * @param loader the class loader to define the proxy class in; null
1233:      *        implies the bootstrap class loader
1234:      * @return the proxy class Class object
1235:      */
1236:     Class generate(ClassLoader loader)
1237:     {
1238:       byte[] bytecode = new byte[pool.length() + stream.length()];
1239:       // More efficient to bypass calling charAt() repetitively.
1240:       char[] c = pool.toString().toCharArray();
1241:       int i = c.length;
1242:       while (--i >= 0)
1243:         bytecode[i] = (byte) c[i];
1244:       c = stream.toString().toCharArray();
1245:       i = c.length;
1246:       int j = bytecode.length;
1247:       while (i > 0)
1248:         bytecode[--j] = (byte) c[--i];
1249: 
1250:       // Patch the constant pool size, which we left at 0 earlier.
1251:       int count = poolEntries.size() + 1;
1252:       bytecode[8] = (byte) (count >> 8);
1253:       bytecode[9] = (byte) count;
1254: 
1255:       try
1256:         {
1257:           Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
1258:           Class[] types = {ClassLoader.class, String.class,
1259:                            byte[].class, int.class, int.class,
1260:                            ProtectionDomain.class };
1261:           Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
1262:           // We can bypass the security check of setAccessible(true), since
1263:           // we're in the same package.
1264:           m.flag = true;
1265: 
1266:           Object[] args = {loader, qualName, bytecode, Integer.valueOf(0),
1267:                            Integer.valueOf(bytecode.length),
1268:                            Object.class.getProtectionDomain() };
1269:           Class clazz = (Class) m.invoke(null, args);
1270: 
1271:           // Finally, initialize the m field of the proxy class, before
1272:           // returning it.
1273:           Field f = clazz.getDeclaredField("m");
1274:           f.flag = true;
1275:           // we can share the array, because it is not publicized
1276:           f.set(null, methods);
1277: 
1278:           return clazz;
1279:         }
1280:       catch (Exception e)
1281:         {
1282:           // assert false;
1283:           throw (Error) new InternalError("Unexpected: " + e).initCause(e);
1284:         }
1285:     }
1286: 
1287:     /**
1288:      * Put a single byte on the stream.
1289:      *
1290:      * @param i the information to add (only lowest 8 bits are used)
1291:      */
1292:     private void putU1(int i)
1293:     {
1294:       stream.append((char) i);
1295:     }
1296: 
1297:     /**
1298:      * Put two bytes on the stream.
1299:      *
1300:      * @param i the information to add (only lowest 16 bits are used)
1301:      */
1302:     private void putU2(int i)
1303:     {
1304:       stream.append((char) (i >> 8)).append((char) i);
1305:     }
1306: 
1307:     /**
1308:      * Put four bytes on the stream.
1309:      *
1310:      * @param i the information to add (treated as unsigned)
1311:      */
1312:     private void putU4(int i)
1313:     {
1314:       stream.append((char) (i >> 24)).append((char) (i >> 16));
1315:       stream.append((char) (i >> 8)).append((char) i);
1316:     }
1317: 
1318:     /**
1319:      * Put bytecode to load a constant integer on the stream. This only
1320:      * needs to work for values less than Short.MAX_VALUE.
1321:      *
1322:      * @param i the int to add
1323:      */
1324:     private void putConst(int i)
1325:     {
1326:       if (i >= -1 && i <= 5)
1327:         putU1(ICONST_0 + i);
1328:       else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
1329:         {
1330:           putU1(BIPUSH);
1331:           putU1(i);
1332:         }
1333:       else
1334:         {
1335:           putU1(SIPUSH);
1336:           putU2(i);
1337:         }
1338:     }
1339: 
1340:     /**
1341:      * Put bytecode to load a given local variable on the stream.
1342:      *
1343:      * @param i the slot to load
1344:      * @param type the base type of the load
1345:      */
1346:     private void putLoad(int i, Class type)
1347:     {
1348:       int offset = 0;
1349:       if (type == long.class)
1350:         offset = 1;
1351:       else if (type == float.class)
1352:         offset = 2;
1353:       else if (type == double.class)
1354:         offset = 3;
1355:       else if (! type.isPrimitive())
1356:         offset = 4;
1357:       if (i < 4)
1358:         putU1(ILOAD_0 + 4 * offset + i);
1359:       else
1360:         {
1361:           putU1(ILOAD + offset);
1362:           putU1(i);
1363:         }
1364:     }
1365: 
1366:     /**
1367:      * Given a primitive type, return its wrapper class name.
1368:      *
1369:      * @param clazz the primitive type (but not void.class)
1370:      * @return the internal form of the wrapper class name
1371:      */
1372:     private String wrapper(Class clazz)
1373:     {
1374:       if (clazz == boolean.class)
1375:         return "java/lang/Boolean";
1376:       if (clazz == byte.class)
1377:         return "java/lang/Byte";
1378:       if (clazz == short.class)
1379:         return "java/lang/Short";
1380:       if (clazz == char.class)
1381:         return "java/lang/Character";
1382:       if (clazz == int.class)
1383:         return "java/lang/Integer";
1384:       if (clazz == long.class)
1385:         return "java/lang/Long";
1386:       if (clazz == float.class)
1387:         return "java/lang/Float";
1388:       if (clazz == double.class)
1389:         return "java/lang/Double";
1390:       // assert false;
1391:       return null;
1392:     }
1393: 
1394:     /**
1395:      * Returns the entry of this String in the Constant pool, adding it
1396:      * if necessary.
1397:      *
1398:      * @param str the String to resolve
1399:      * @return the index of the String in the constant pool
1400:      */
1401:     private char utf8Info(String str)
1402:     {
1403:       String utf8 = toUtf8(str);
1404:       int len = utf8.length();
1405:       return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
1406:     }
1407: 
1408:     /**
1409:      * Returns the entry of the appropriate class info structure in the
1410:      * Constant pool, adding it if necessary.
1411:      *
1412:      * @param name the class name, in internal form
1413:      * @return the index of the ClassInfo in the constant pool
1414:      */
1415:     private char classInfo(String name)
1416:     {
1417:       char index = utf8Info(name);
1418:       char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
1419:       return poolIndex(new String(c));
1420:     }
1421: 
1422:     /**
1423:      * Returns the entry of the appropriate class info structure in the
1424:      * Constant pool, adding it if necessary.
1425:      *
1426:      * @param clazz the class type
1427:      * @return the index of the ClassInfo in the constant pool
1428:      */
1429:     private char classInfo(Class clazz)
1430:     {
1431:       return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
1432:                                                         false));
1433:     }
1434: 
1435:     /**
1436:      * Returns the entry of the appropriate fieldref, methodref, or
1437:      * interfacemethodref info structure in the Constant pool, adding it
1438:      * if necessary.
1439:      *
1440:      * @param structure FIELD, METHOD, or INTERFACE
1441:      * @param clazz the class name, in internal form
1442:      * @param name the simple reference name
1443:      * @param type the type of the reference
1444:      * @return the index of the appropriate Info structure in the constant pool
1445:      */
1446:     private char refInfo(byte structure, String clazz, String name,
1447:                          String type)
1448:     {
1449:       char cindex = classInfo(clazz);
1450:       char ntindex = nameAndTypeInfo(name, type);
1451:       // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
1452:       char[] c = {(char) (structure + 8),
1453:                   (char) (cindex >> 8), (char) (cindex & 0xff),
1454:                   (char) (ntindex >> 8), (char) (ntindex & 0xff)};
1455:       return poolIndex(new String(c));
1456:     }
1457: 
1458:     /**
1459:      * Returns the entry of the appropriate nameAndTyperef info structure
1460:      * in the Constant pool, adding it if necessary.
1461:      *
1462:      * @param name the simple name
1463:      * @param type the reference type
1464:      * @return the index of the NameAndTypeInfo structure in the constant pool
1465:      */
1466:     private char nameAndTypeInfo(String name, String type)
1467:     {
1468:       char nindex = utf8Info(name);
1469:       char tindex = utf8Info(type);
1470:       char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
1471:                   (char) (tindex >> 8), (char) (tindex & 0xff)};
1472:       return poolIndex(new String(c));
1473:     }
1474: 
1475:     /**
1476:      * Converts a regular string to a UTF8 string, where the upper byte
1477:      * of every char is 0, and '\\u0000' is not in the string.  This is
1478:      * basically to use a String as a fancy byte[], and while it is less
1479:      * efficient in memory use, it is easier for hashing.
1480:      *
1481:      * @param str the original, in straight unicode
1482:      * @return a modified string, in UTF8 format in the low bytes
1483:      */
1484:     private String toUtf8(String str)
1485:     {
1486:       final char[] ca = str.toCharArray();
1487:       final int len = ca.length;
1488: 
1489:       // Avoid object creation, if str is already fits UTF8.
1490:       int i;
1491:       for (i = 0; i < len; i++)
1492:         if (ca[i] == 0 || ca[i] > '\u007f')
1493:           break;
1494:       if (i == len)
1495:         return str;
1496: 
1497:       final CPStringBuilder sb = new CPStringBuilder(str);
1498:       sb.setLength(i);
1499:       for ( ; i < len; i++)
1500:         {
1501:           final char c = ca[i];
1502:           if (c > 0 && c <= '\u007f')
1503:             sb.append(c);
1504:           else if (c <= '\u07ff') // includes '\0'
1505:             {
1506:               sb.append((char) (0xc0 | (c >> 6)));
1507:               sb.append((char) (0x80 | (c & 0x6f)));
1508:             }
1509:           else
1510:             {
1511:               sb.append((char) (0xe0 | (c >> 12)));
1512:               sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
1513:               sb.append((char) (0x80 | (c & 0x6f)));
1514:             }
1515:         }
1516:       return sb.toString();
1517:     }
1518: 
1519:     /**
1520:      * Returns the location of a byte sequence (conveniently wrapped in
1521:      * a String with all characters between \u0001 and \u00ff inclusive)
1522:      * in the constant pool, adding it if necessary.
1523:      *
1524:      * @param sequence the byte sequence to look for
1525:      * @return the index of the sequence
1526:      * @throws IllegalArgumentException if this would make the constant
1527:      *         pool overflow
1528:      */
1529:     private char poolIndex(String sequence)
1530:     {
1531:       Integer i = (Integer) poolEntries.get(sequence);
1532:       if (i == null)
1533:         {
1534:           // pool starts at index 1
1535:           int size = poolEntries.size() + 1;
1536:           if (size >= 65535)
1537:             throw new IllegalArgumentException("exceeds VM limitations");
1538:           i = Integer.valueOf(size);
1539:           poolEntries.put(sequence, i);
1540:           pool.append(sequence);
1541:         }
1542:       return (char) i.intValue();
1543:     }
1544:   } // class ClassFactory
1545: }