Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: java/lang/reflect/Proxy.java


1   /* Proxy.java -- build a proxy class that implements reflected interfaces
2      Copyright (C) 2001, 2002, 2003, 2004, 2005  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.HashMap;
46  import java.util.HashSet;
47  import java.util.Iterator;
48  import java.util.Map;
49  import java.util.Set;
50  
51  /**
52   * This class allows you to dynamically create an instance of any (or
53   * even multiple) interfaces by reflection, and decide at runtime
54   * how that instance will behave by giving it an appropriate
55   * {@link InvocationHandler}.  Proxy classes serialize specially, so
56   * that the proxy object can be reused between VMs, without requiring
57   * a persistent copy of the generated class code.
58   *
59   * <h3>Creation</h3>
60   * To create a proxy for some interface Foo:
61   *
62   * <pre>
63   *   InvocationHandler handler = new MyInvocationHandler(...);
64   *   Class proxyClass = Proxy.getProxyClass(
65   *       Foo.class.getClassLoader(), new Class[] { Foo.class });
66   *   Foo f = (Foo) proxyClass
67   *       .getConstructor(new Class[] { InvocationHandler.class })
68   *       .newInstance(new Object[] { handler });
69   * </pre>
70   * or more simply:
71   * <pre>
72   *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
73   *                                        new Class[] { Foo.class },
74   *                                        handler);
75   * </pre>
76   *
77   * <h3>Dynamic Proxy Classes</h3>
78   * A dynamic proxy class is created at runtime, and has the following
79   * properties:
80   * <ul>
81   *  <li>The class is <code>public</code> and <code>final</code>,
82   *      and is neither <code>abstract</code> nor an inner class.</li>
83   *  <li>The class has no canonical name (there is no formula you can use
84   *      to determine or generate its name), but begins with the
85   *      sequence "$Proxy".  Abuse this knowledge at your own peril.
86   *      (For now, '$' in user identifiers is legal, but it may not
87   *      be that way forever. You weren't using '$' in your
88   *      identifiers, were you?)</li>
89   *  <li>The class extends Proxy, and explicitly implements all the
90   *      interfaces specified at creation, in order (this is important
91   *      for determining how method invocation is resolved).  Note that
92   *      a proxy class implements {@link Serializable}, at least
93   *      implicitly, since Proxy does, but true serial behavior
94   *      depends on using a serializable invocation handler as well.</li>
95   *  <li>If at least one interface is non-public, the proxy class
96   *      will be in the same package.  Otherwise, the package is
97   *      unspecified.  This will work even if the package is sealed
98   *      from user-generated classes, because Proxy classes are
99   *      generated by a trusted source.  Meanwhile, the proxy class
100  *      belongs to the classloader you designated.</li>
101  *  <li>Reflection works as expected: {@link Class#getInterfaces()} and
102  *      {@link Class#getMethods()} work as they do on normal classes.</li>
103  *  <li>The method {@link #isProxyClass()} will distinguish between
104  *      true proxy classes and user extensions of this class.  It only
105  *      returns true for classes created by {@link #getProxyClass}.</li>
106  *  <li>The {@link ProtectionDomain} of a proxy class is the same as for
107  *      bootstrap classes, such as Object or Proxy, since it is created by
108  *      a trusted source.  This protection domain will typically be granted
109  *      {@link java.security.AllPermission}. But this is not a security
110  *      risk, since there are adequate permissions on reflection, which is
111  *      the only way to create an instance of the proxy class.</li>
112  *  <li>The proxy class contains a single constructor, which takes as
113  *      its only argument an {@link InvocationHandler}.  The method
114  *      {@link #newInstance} is shorthand to do the necessary
115  *      reflection.</li>
116  * </ul>
117  *
118  * <h3>Proxy Instances</h3>
119  * A proxy instance is an instance of a proxy class.  It has the
120  * following properties, many of which follow from the properties of a
121  * proxy class listed above:
122  * <ul>
123  *  <li>For a proxy class with Foo listed as one of its interfaces, the
124  *      expression <code>proxy instanceof Foo</code> will return true,
125  *      and the expression <code>(Foo) proxy</code> will succeed without
126  *      a {@link ClassCastException}.</li>
127  *  <li>Each proxy instance has an invocation handler, which can be
128  *      accessed by {@link #getInvocationHandler(Object)}.  Any call
129  *      to an interface method, including {@link Object#hashcode()},
130  *      {@link Object#equals(Object)}, or {@link Object#toString()},
131  *      but excluding the public final methods of Object, will be
132  *      encoded and passed to the {@link InvocationHandler#invoke}
133  *      method of this handler.</li>
134  * </ul>
135  *
136  * <h3>Inheritance Issues</h3>
137  * A proxy class may inherit a method from more than one interface.
138  * The order in which interfaces are listed matters, because it determines
139  * which reflected {@link Method} object will be passed to the invocation
140  * handler.  This means that the dynamically generated class cannot
141  * determine through which interface a method is being invoked.<p>
142  *
143  * In short, if a method is declared in Object (namely, hashCode,
144  * equals, or toString), then Object will be used; otherwise, the
145  * leftmost interface that inherits or declares a method will be used,
146  * even if it has a more permissive throws clause than what the proxy
147  * class is allowed. Thus, in the invocation handler, it is not always
148  * safe to assume that every class listed in the throws clause of the
149  * passed Method object can safely be thrown; fortunately, the Proxy
150  * instance is robust enough to wrap all illegal checked exceptions in
151  * {@link UndeclaredThrowableException}.
152  *
153  * @see InvocationHandler
154  * @see UndeclaredThrowableException
155  * @see Class
156  * @author Eric Blake (ebb9@email.byu.edu)
157  * @since 1.3
158  * @status updated to 1.4, except for the use of ProtectionDomain
159  */
160 public class Proxy implements Serializable
161 {
162   /**
163    * Compatible with JDK 1.3+.
164    */
165   private static final long serialVersionUID = -2222568056686623797L;
166 
167   /**
168    * Map of ProxyType to proxy class.
169    *
170    * @XXX This prevents proxy classes from being garbage collected.
171    * java.util.WeakHashSet is not appropriate, because that collects the
172    * keys, but we are interested in collecting the elements.
173    */
174   private static final Map proxyClasses = new HashMap();
175 
176   /**
177    * The invocation handler for this proxy instance.  For Proxy, this
178    * field is unused, but it appears here in order to be serialized in all
179    * proxy classes.
180    *
181    * <em>NOTE</em>: This implementation is more secure for proxy classes
182    * than what Sun specifies. Sun does not require h to be immutable, but
183    * this means you could change h after the fact by reflection.  However,
184    * by making h immutable, we may break non-proxy classes which extend
185    * Proxy.
186    * @serial invocation handler associated with this proxy instance
187    */
188   protected InvocationHandler h;
189 
190   /**
191    * Constructs a new Proxy from a subclass (usually a proxy class),
192    * with the specified invocation handler.
193    *
194    * <em>NOTE</em>: This throws a NullPointerException if you attempt
195    * to create a proxy instance with a null handler using reflection.
196    * This behavior is not yet specified by Sun; see Sun Bug 4487672.
197    *
198    * @param handler the invocation handler, may be null if the subclass
199    *        is not a proxy class
200    * @throws NullPointerException if handler is null and this is a proxy
201    *         instance
202    */
203   protected Proxy(InvocationHandler handler)
204   {
205     if (handler == null && isProxyClass(getClass()))
206       throw new NullPointerException("invalid handler");
207     h = handler;
208   }
209 
210   /**
211    * Returns the proxy {@link Class} for the given ClassLoader and array
212    * of interfaces, dynamically generating it if necessary.
213    *
214    * <p>There are several restrictions on this method, the violation of
215    * which will result in an IllegalArgumentException or
216    * NullPointerException:</p>
217    * 
218    * <ul>
219    * <li>All objects in `interfaces' must represent distinct interfaces.
220    *     Classes, primitive types, null, and duplicates are forbidden.</li>
221    * <li>The interfaces must be visible in the specified ClassLoader.
222    *     In other words, for each interface i:
223    *     <code>Class.forName(i.getName(), false, loader) == i</code>
224    *     must be true.</li>
225    * <li>All non-public interfaces (if any) must reside in the same
226    *     package, or the proxy class would be non-instantiable.  If
227    *     there are no non-public interfaces, the package of the proxy
228    *     class is unspecified.</li>
229    * <li>All interfaces must be compatible - if two declare a method
230    *     with the same name and parameters, the return type must be
231    *     the same and the throws clause of the proxy class will be
232    *     the maximal subset of subclasses of the throws clauses for
233    *     each method that is overridden.</li>
234    * <li>VM constraints limit the number of interfaces a proxy class
235    *     may directly implement (however, the indirect inheritance
236    *     of {@link Serializable} does not count against this limit).
237    *     Even though most VMs can theoretically have 65535
238    *     superinterfaces for a class, the actual limit is smaller
239    *     because a class's constant pool is limited to 65535 entries,
240    *     and not all entries can be interfaces.</li>
241    * </ul>
242    *
243    * <p>Note that different orders of interfaces produce distinct classes.</p>
244    *
245    * @param loader the class loader to define the proxy class in; null
246    *        implies the bootstrap class loader
247    * @param interfaces the array of interfaces the proxy class implements,
248    *        may be empty, but not null
249    * @return the Class object of the proxy class
250    * @throws IllegalArgumentException if the constraints above were
251    *         violated, except for problems with null
252    * @throws NullPointerException if `interfaces' is null or contains
253    *         a null entry
254    */
255   // synchronized so that we aren't trying to build the same class
256   // simultaneously in two threads
257   public static synchronized Class getProxyClass(ClassLoader loader,
258                                                  Class[] interfaces)
259   {
260     interfaces = (Class[]) interfaces.clone();
261     ProxyType pt = new ProxyType(loader, interfaces);
262     Class clazz = (Class) proxyClasses.get(pt);
263     if (clazz == null)
264       {
265         if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
266           clazz = VMProxy.getProxyClass(loader, interfaces);
267         else
268           {
269             ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
270                               ? VMProxy.getProxyData(loader, interfaces)
271                               : ProxyData.getProxyData(pt));
272 
273             clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
274          ? VMProxy.generateProxyClass(loader, data)
275                      : new ClassFactory(data).generate(loader));
276           }
277 
278         Object check = proxyClasses.put(pt, clazz);
279         // assert check == null && clazz != null;
280         if (check != null || clazz == null)
281           throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
282       }
283     return clazz;
284   }
285 
286   /**
287    * Combines several methods into one.  This is equivalent to:
288    * <pre>
289    *   Proxy.getProxyClass(loader, interfaces)
290    *       .getConstructor(new Class[] {InvocationHandler.class})
291    *       .newInstance(new Object[] {handler});
292    * </pre>
293    * except that it will not fail with the normal problems caused
294    * by reflection.  It can still fail for the same reasons documented
295    * in getProxyClass, or if handler is null.
296    *
297    * @param loader the class loader to define the proxy class in; null
298    *        implies the bootstrap class loader
299    * @param interfaces the array of interfaces the proxy class implements,
300    *        may be empty, but not null
301    * @param handler the invocation handler, may not be null
302    * @return a proxy instance implementing the specified interfaces
303    * @throws IllegalArgumentException if the constraints for getProxyClass
304    *         were violated, except for problems with null
305    * @throws NullPointerException if `interfaces' is null or contains
306    *         a null entry, or if handler is null
307    * @see #getProxyClass(ClassLoader, Class[])
308    * @see Class#getConstructor(Class[])
309    * @see Constructor#newInstance(Object[])
310    */
311   public static Object newProxyInstance(ClassLoader loader,
312                                         Class[] interfaces,
313                                         InvocationHandler handler)
314   {
315     try
316       {
317         // getProxyClass() and Proxy() throw the necessary exceptions
318         return getProxyClass(loader, interfaces)
319           .getConstructor(new Class[] {InvocationHandler.class})
320           .newInstance(new Object[] {handler});
321       }
322     catch (RuntimeException e)
323       {
324         // Let IllegalArgumentException, NullPointerException escape.
325         // assert e instanceof IllegalArgumentException
326         //   || e instanceof NullPointerException;
327         throw e;
328       }
329     catch (InvocationTargetException e)
330       {
331         // Let wrapped NullPointerException escape.
332         // assert e.getTargetException() instanceof NullPointerException
333         throw (NullPointerException) e.getCause();
334       }
335     catch (Exception e)
336       {
337         // Covers InstantiationException, IllegalAccessException,
338         // NoSuchMethodException, none of which should be generated
339         // if the proxy class was generated correctly.
340         // assert false;
341         throw (Error) new InternalError("Unexpected: " + e).initCause(e);
342       }
343   }
344 
345   /**
346    * Returns true if and only if the Class object is a dynamically created
347    * proxy class (created by <code>getProxyClass</code> or by the
348    * syntactic sugar of <code>newProxyInstance</code>).
349    *
350    * <p>This check is secure (in other words, it is not simply
351    * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
352    * be spoofed by non-proxy classes that extend Proxy.
353    *
354    * @param clazz the class to check, must not be null
355    * @return true if the class represents a proxy class
356    * @throws NullPointerException if clazz is null
357    */
358   // This is synchronized on the off chance that another thread is
359   // trying to add a class to the map at the same time we read it.
360   public static synchronized boolean isProxyClass(Class clazz)
361   {
362     if (! Proxy.class.isAssignableFrom(clazz))
363       return false;
364     // This is a linear search, even though we could do an O(1) search
365     // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
366     return proxyClasses.containsValue(clazz);
367   }
368 
369   /**
370    * Returns the invocation handler for the given proxy instance.<p>
371    *
372    * <em>NOTE</em>: We guarantee a non-null result if successful,
373    * but Sun allows the creation of a proxy instance with a null
374    * handler.  See the comments for {@link #Proxy(InvocationHandler)}.
375    *
376    * @param proxy the proxy instance, must not be null
377    * @return the invocation handler, guaranteed non-null.
378    * @throws IllegalArgumentException if
379    *         <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
380    * @throws NullPointerException if proxy is null
381    */
382   public static InvocationHandler getInvocationHandler(Object proxy)
383   {
384     if (! isProxyClass(proxy.getClass()))
385       throw new IllegalArgumentException("not a proxy instance");
386     return ((Proxy) proxy).h;
387   }
388 
389   /**
390    * Helper class for mapping unique ClassLoader and interface combinations
391    * to proxy classes.
392    *
393    * @author Eric Blake (ebb9@email.byu.edu)
394    */
395   private static final class ProxyType
396   {
397     /**
398      * Store the class loader (may be null)
399      */
400     final ClassLoader loader;
401 
402     /**
403      * Store the interfaces (never null, all elements are interfaces)
404      */
405     final Class[] interfaces;
406 
407     /**
408      * Construct the helper object.
409      *
410      * @param loader the class loader to define the proxy class in; null
411      *        implies the bootstrap class loader
412      * @param interfaces an array of interfaces
413      */
414     ProxyType(ClassLoader loader, Class[] interfaces)
415     {
416       if (loader == null)
417          loader = ClassLoader.getSystemClassLoader();
418       this.loader = loader;
419       this.interfaces = interfaces;
420     }
421 
422     /**
423      * Calculates the hash code.
424      *
425      * @return a combination of the classloader and interfaces hashcodes.
426      */
427     public int hashCode()
428     {
429       //loader is always not null
430       int hash = 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 the 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", null));
477           coreMethods.put(sig, sig);
478           sig = new ProxySignature(Object.class.getMethod("toString", null));
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 the 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               ProxySignature sig = new ProxySignature(methods[j]);
739               ProxySignature old = (ProxySignature) method_set.put(sig, sig);
740               if (old != null)
741                 sig.checkCompatibility(old);
742             }
743         }
744 
745       i = method_set.size();
746       data.methods = new Method[i];
747       data.exceptions = new Class[i][];
748       Iterator itr = method_set.values().iterator();
749       while (--i >= 0)
750         {
751           ProxySignature sig = (ProxySignature) itr.next();
752           data.methods[i] = sig.method;
753           data.exceptions[i] = (Class[]) sig.exceptions
754             .toArray(new Class[sig.exceptions.size()]);
755         }
756       return data;
757     }
758   } // class ProxyData
759 
760   /**
761    * Does all the work of building a class. By making this a nested class,
762    * this code is not loaded in memory if the VM has a native
763    * implementation instead.
764    *
765    * @author Eric Blake (ebb9@email.byu.edu)
766    */
767   private static final class ClassFactory
768   {
769     /** Constants for assisting the compilation */
770     private static final byte FIELD = 1;
771     private static final byte METHOD = 2;
772     private static final byte INTERFACE = 3;
773     private static final String CTOR_SIG
774       = "(Ljava/lang/reflect/InvocationHandler;)V";
775     private static final String INVOKE_SIG = "(Ljava/lang/Object;"
776       + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
777 
778     /** Bytecodes for insertion in the class definition byte[] */
779     private static final char ACONST_NULL = 1;
780     private static final char ICONST_0 = 3;
781     private static final char BIPUSH = 16;
782     private static final char SIPUSH = 17;
783     private static final char ILOAD = 21;
784     private static final char ILOAD_0 = 26;
785     private static final char ALOAD_0 = 42;
786     private static final char ALOAD_1 = 43;
787     private static final char AALOAD = 50;
788     private static final char AASTORE = 83;
789     private static final char DUP = 89;
790     private static final char DUP_X1 = 90;
791     private static final char SWAP = 95;
792     private static final char IRETURN = 172;
793     private static final char LRETURN = 173;
794     private static final char FRETURN = 174;
795     private static final char DRETURN = 175;
796     private static final char ARETURN = 176;
797     private static final char RETURN = 177;
798     private static final char GETSTATIC = 178;
799     private static final char GETFIELD = 180;
800     private static final char INVOKEVIRTUAL = 182;
801     private static final char INVOKESPECIAL = 183;
802     private static final char INVOKEINTERFACE = 185;
803     private static final char NEW = 187;
804     private static final char ANEWARRAY = 189;
805     private static final char ATHROW = 191;
806     private static final char CHECKCAST = 192;
807 
808     // Implementation note: we use StringBuffers to hold the byte data, since
809     // they automatically grow.  However, we only use the low 8 bits of
810     // every char in the array, so we are using twice the necessary memory
811     // for the ease StringBuffer provides.
812 
813     /** The constant pool. */
814     private final StringBuffer pool = new StringBuffer();
815     /** The rest of the class data. */
816     private final StringBuffer stream = new StringBuffer();
817 
818     /** Map of strings to byte sequences, to minimize size of pool. */
819     private final Map poolEntries = new HashMap();
820 
821     /** The VM name of this proxy class. */
822     private final String qualName;
823 
824     /**
825      * The Method objects the proxy class refers to when calling the
826      * invocation handler.
827      */
828     private final Method[] methods;
829 
830     /**
831      * Initializes the buffers with the bytecode contents for a proxy class.
832      *
833      * @param data the remainder of the class data
834      * @throws IllegalArgumentException if anything else goes wrong this
835      *         late in the game; as far as I can tell, this will only happen
836      *         if the constant pool overflows, which is possible even when
837      *         the user doesn't exceed the 65535 interface limit
838      */
839     ClassFactory(ProxyData data)
840     {
841       methods = data.methods;
842 
843       // magic = 0xcafebabe
844       // minor_version = 0
845       // major_version = 46
846       // constant_pool_count: place-holder for now
847       pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
848       // constant_pool[], filled in as we go
849 
850       // access_flags
851       putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
852       // this_class
853       qualName = (data.pack + "$Proxy" + data.id);
854       putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
855       // super_class
856       putU2(classInfo("java/lang/reflect/Proxy"));
857 
858       // interfaces_count
859       putU2(data.interfaces.length);
860       // interfaces[]
861       for (int i = 0; i < data.interfaces.length; i++)
862         putU2(classInfo(data.interfaces[i]));
863 
864       // Recall that Proxy classes serialize specially, so we do not need
865       // to worry about a <clinit> method for this field.  Instead, we
866       // just assign it by reflection after the class is successfully loaded.
867       // fields_count - private static Method[] m;
868       putU2(1);
869       // fields[]
870       // m.access_flags
871       putU2(Modifier.PRIVATE | Modifier.STATIC);
872       // m.name_index
873       putU2(utf8Info("m"));
874       // m.descriptor_index
875       putU2(utf8Info("[Ljava/lang/reflect/Method;"));
876       // m.attributes_count
877       putU2(0);
878       // m.attributes[]
879 
880       // methods_count - # handler methods, plus <init>
881       putU2(methods.length + 1);
882       // methods[]
883       // <init>.access_flags
884       putU2(Modifier.PUBLIC);
885       // <init>.name_index
886       putU2(utf8Info("<init>"));
887       // <init>.descriptor_index
888       putU2(utf8Info(CTOR_SIG));
889       // <init>.attributes_count - only Code is needed
890       putU2(1);
891       // <init>.Code.attribute_name_index
892       putU2(utf8Info("Code"));
893       // <init>.Code.attribute_length = 18
894       // <init>.Code.info:
895       //   $Proxynn(InvocationHandler h) { super(h); }
896       // <init>.Code.max_stack = 2
897       // <init>.Code.max_locals = 2
898       // <init>.Code.code_length = 6
899       // <init>.Code.code[]
900       stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
901                     + INVOKESPECIAL);
902       putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
903       // <init>.Code.exception_table_length = 0
904       // <init>.Code.exception_table[]
905       // <init>.Code.attributes_count = 0
906       // <init>.Code.attributes[]
907       stream.append(RETURN + "\0\0\0\0");
908 
909       for (int i = methods.length - 1; i >= 0; i--)
910         emitMethod(i, data.exceptions[i]);
911 
912       // attributes_count
913       putU2(0);
914       // attributes[] - empty; omit SourceFile attribute
915       // XXX should we mark this with a Synthetic attribute?
916     }
917 
918     /**
919      * Produce the bytecode for a single method.
920      *
921      * @param i the index of the method we are building
922      * @param e the exceptions possible for the method
923      */
924     private void emitMethod(int i, Class[] e)
925     {
926       // First, we precalculate the method length and other information.
927 
928       Method m = methods[i];
929       Class[] paramtypes = m.getParameterTypes();
930       int wrap_overhead = 0; // max words taken by wrapped primitive
931       int param_count = 1; // 1 for this
932       int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
933       // aaload, const/aconst_null, invokeinterface
934       if (i > 5)
935         {
936           if (i > Byte.MAX_VALUE)
937             code_length += 2; // sipush
938           else
939             code_length++; // bipush
940         }
941       if (paramtypes.length > 0)
942         {
943           code_length += 3; // anewarray
944           if (paramtypes.length > Byte.MAX_VALUE)
945             code_length += 2; // sipush
946           else if (paramtypes.length > 5)
947             code_length++; // bipush
948           for (int j = 0; j < paramtypes.length; j++)
949             {
950               code_length += 4; // dup, const, load, store
951               Class type = paramtypes[j];
952               if (j > 5)
953                 {
954                   if (j > Byte.MAX_VALUE)
955                     code_length += 2; // sipush
956                   else
957                     code_length++; // bipush
958                 }
959               if (param_count >= 4)
960                 code_length++; // 2-byte load
961               param_count++;
962               if (type.isPrimitive())
963                 {
964                   code_length += 7; // new, dup, invokespecial
965                   if (type == long.class || type == double.class)
966                     {
967                       wrap_overhead = 3;
968                       param_count++;
969                     }
970                   else if (wrap_overhead < 2)
971                     wrap_overhead = 2;
972                 }
973             }
974         }
975       int end_pc = code_length;
976       Class ret_type = m.getReturnType();
977       if (ret_type == void.class)
978         code_length++; // return
979       else if (ret_type.isPrimitive())
980         code_length += 7; // cast, invokevirtual, return
981       else
982         code_length += 4; // cast, return
983       int exception_count = 0;
984       boolean throws_throwable = false;
985       for (int j = 0; j < e.length; j++)
986         if (e[j] == Throwable.class)
987           {
988             throws_throwable = true;
989             break;
990           }
991       if (! throws_throwable)
992         {
993           exception_count = e.length + 3; // Throwable, Error, RuntimeException
994           code_length += 9; // new, dup_x1, swap, invokespecial, athrow
995         }
996       int handler_pc = code_length - 1;
997       StringBuffer signature = new StringBuffer("(");
998       for (int j = 0; j < paramtypes.length; j++)
999         signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
1000      signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
1001
1002      // Now we have enough information to emit the method.
1003
1004      // handler.access_flags
1005      putU2(Modifier.PUBLIC | Modifier.FINAL);
1006      // handler.name_index
1007      putU2(utf8Info(m.getName()));
1008      // handler.descriptor_index
1009      putU2(utf8Info(signature.toString()));
1010      // handler.attributes_count - Code is necessary, Exceptions possible
1011      putU2(e.length > 0 ? 2 : 1);
1012
1013      // handler.Code.info:
1014      //   type name(args) {
1015      //     try {
1016      //       return (type) h.invoke(this, methods[i], new Object[] {args});
1017      //     } catch (<declared Exceptions> e) {
1018      //       throw e;
1019      //     } catch (Throwable t) {
1020      //       throw new UndeclaredThrowableException(t);
1021      //     }
1022      //   }
1023      // Special cases:
1024      //  if arg_n is primitive, wrap it
1025      //  if method throws Throwable, try-catch is not needed
1026      //  if method returns void, return statement not needed
1027      //  if method returns primitive, unwrap it
1028      //  save space by sharing code for all the declared handlers
1029
1030      // handler.Code.attribute_name_index
1031      putU2(utf8Info("Code"));
1032      // handler.Code.attribute_length
1033      putU4(12 + code_length + 8 * exception_count);
1034      // handler.Code.max_stack
1035      putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
1036      // handler.Code.max_locals
1037      putU2(param_count);
1038      // handler.Code.code_length
1039      putU4(code_length);
1040      // handler.Code.code[]
1041      putU1(ALOAD_0);
1042      putU1(GETFIELD);
1043      putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
1044                    "Ljava/lang/reflect/InvocationHandler;"));
1045      putU1(ALOAD_0);
1046      putU1(GETSTATIC);
1047      putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
1048                    "m", "[Ljava/lang/reflect/Method;"));
1049      putConst(i);
1050      putU1(AALOAD);
1051      if (paramtypes.length > 0)
1052        {
1053          putConst(paramtypes.length);
1054          putU1(ANEWARRAY);
1055          putU2(classInfo("java/lang/Object"));
1056          param_count = 1;
1057          for (int j = 0; j < paramtypes.length; j++, param_count++)
1058            {
1059              putU1(DUP);
1060              putConst(j);
1061              if (paramtypes[j].isPrimitive())
1062                {
1063                  putU1(NEW);
1064                  putU2(classInfo(wrapper(paramtypes[j])));
1065                  putU1(DUP);
1066                }
1067              putLoad(param_count, paramtypes[j]);
1068              if (paramtypes[j].isPrimitive())
1069                {
1070                  putU1(INVOKESPECIAL);
1071                  putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
1072                                '(' + (TypeSignature
1073                                       .getEncodingOfClass(paramtypes[j])
1074                                       + ")V")));
1075                  if (paramtypes[j] == long.class
1076                      || paramtypes[j] == double.class)
1077                    param_count++;
1078                }
1079              putU1(AASTORE);
1080            }
1081        }
1082      else
1083        putU1(ACONST_NULL);
1084      putU1(INVOKEINTERFACE);
1085      putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
1086                    "invoke", INVOKE_SIG));
1087      putU1(4); // InvocationHandler, this, Method, Object[]
1088      putU1(0);
1089      if (ret_type == void.class)
1090        putU1(RETURN);
1091      else if (ret_type.isPrimitive())
1092        {
1093          putU1(CHECKCAST);
1094          putU2(classInfo(wrapper(ret_type)));
1095          putU1(INVOKEVIRTUAL);
1096          putU2(refInfo(METHOD, wrapper(ret_type),
1097                        ret_type.getName() + "Value",
1098                        "()" + TypeSignature.getEncodingOfClass(ret_type)));
1099          if (ret_type == long.class)
1100            putU1(LRETURN);
1101          else if (ret_type == float.class)
1102            putU1(FRETURN);
1103          else if (ret_type == double.class)
1104            putU1(DRETURN);
1105          else
1106            putU1(IRETURN);
1107        }
1108      else
1109        {
1110          putU1(CHECKCAST);
1111          putU2(classInfo(ret_type));
1112          putU1(ARETURN);
1113        }
1114      if (! throws_throwable)
1115        {
1116          putU1(NEW);
1117          putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
1118          putU1(DUP_X1);
1119          putU1(SWAP);
1120          putU1(INVOKESPECIAL);
1121          putU2(refInfo(METHOD,
1122                        "java/lang/reflect/UndeclaredThrowableException",
1123                        "<init>", "(Ljava/lang/Throwable;)V"));
1124          putU1(ATHROW);
1125        }
1126
1127      // handler.Code.exception_table_length
1128      putU2(exception_count);
1129      // handler.Code.exception_table[]
1130      if (! throws_throwable)
1131        {
1132          // handler.Code.exception_table.start_pc
1133          putU2(0);
1134          // handler.Code.exception_table.end_pc
1135          putU2(end_pc);
1136          // handler.Code.exception_table.handler_pc
1137          putU2(handler_pc);
1138          // handler.Code.exception_table.catch_type
1139          putU2(classInfo("java/lang/Error"));
1140          // handler.Code.exception_table.start_pc
1141          putU2(0);
1142          // handler.Code.exception_table.end_pc
1143          putU2(end_pc);
1144          // handler.Code.exception_table.handler_pc
1145          putU2(handler_pc);
1146          // handler.Code.exception_table.catch_type
1147          putU2(classInfo("java/lang/RuntimeException"));
1148          for (int j = 0; j < e.length; j++)
1149            {
1150              // handler.Code.exception_table.start_pc
1151              putU2(0);
1152              // handler.Code.exception_table.end_pc
1153              putU2(end_pc);
1154              // handler.Code.exception_table.handler_pc
1155              putU2(handler_pc);
1156              // handler.Code.exception_table.catch_type
1157              putU2(classInfo(e[j]));
1158            }
1159          // handler.Code.exception_table.start_pc
1160          putU2(0);
1161          // handler.Code.exception_table.end_pc
1162          putU2(end_pc);
1163          // handler.Code.exception_table.handler_pc -
1164          //   -8 for undeclared handler, which falls thru to normal one
1165          putU2(handler_pc - 8);
1166          // handler.Code.exception_table.catch_type
1167          putU2(0);
1168        }
1169      // handler.Code.attributes_count
1170      putU2(0);
1171      // handler.Code.attributes[]
1172
1173      if (e.length > 0)
1174        {
1175          // handler.Exceptions.attribute_name_index
1176          putU2(utf8Info("Exceptions"));
1177          // handler.Exceptions.attribute_length
1178          putU4(2 * e.length + 2);
1179          // handler.Exceptions.number_of_exceptions
1180          putU2(e.length);
1181          // handler.Exceptions.exception_index_table[]
1182          for (int j = 0; j < e.length; j++)
1183            putU2(classInfo(e[j]));
1184        }
1185    }
1186
1187    /**
1188     * Creates the Class object that corresponds to the bytecode buffers
1189     * built when this object was constructed.
1190     *
1191     * @param loader the class loader to define the proxy class in; null
1192     *        implies the bootstrap class loader
1193     * @return the proxy class Class object
1194     */
1195    Class generate(ClassLoader loader)
1196    {
1197      byte[] bytecode = new byte[pool.length() + stream.length()];
1198      // More efficient to bypass calling charAt() repetitively.
1199      char[] c = pool.toString().toCharArray();
1200      int i = c.length;
1201      while (--i >= 0)
1202        bytecode[i] = (byte) c[i];
1203      c = stream.toString().toCharArray();
1204      i = c.length;
1205      int j = bytecode.length;
1206      while (i > 0)
1207        bytecode[--j] = (byte) c[--i];
1208
1209      // Patch the constant pool size, which we left at 0 earlier.
1210      int count = poolEntries.size() + 1;
1211      bytecode[8] = (byte) (count >> 8);
1212      bytecode[9] = (byte) count;
1213
1214      try
1215        {
1216          Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
1217          Class[] types = {ClassLoader.class, String.class,
1218                           byte[].class, int.class, int.class,
1219                           ProtectionDomain.class };
1220          Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
1221          // We can bypass the security check of setAccessible(true), since
1222    // we're in the same package.
1223          m.flag = true;
1224
1225          Object[] args = {loader, qualName, bytecode, new Integer(0),
1226                           new Integer(bytecode.length),
1227                           Object.class.getProtectionDomain() };
1228          Class clazz = (Class) m.invoke(null, args);
1229
1230          // Finally, initialize the m field of the proxy class, before
1231          // returning it.
1232          Field f = clazz.getDeclaredField("m");
1233          f.flag = true;
1234          // we can share the array, because it is not publicized
1235          f.set(null, methods);
1236
1237          return clazz;
1238        }
1239      catch (Exception e)
1240        {
1241          // assert false;
1242          throw (Error) new InternalError("Unexpected: " + e).initCause(e);
1243        }
1244    }
1245
1246    /**
1247     * Put a single byte on the stream.
1248     *
1249     * @param i the information to add (only lowest 8 bits are used)
1250     */
1251    private void putU1(int i)
1252    {
1253      stream.append((char) i);
1254    }
1255
1256    /**
1257     * Put two bytes on the stream.
1258     *
1259     * @param i the information to add (only lowest 16 bits are used)
1260     */
1261    private void putU2(int i)
1262    {
1263      stream.append((char) (i >> 8)).append((char) i);
1264    }
1265
1266    /**
1267     * Put four bytes on the stream.
1268     *
1269     * @param i the information to add (treated as unsigned)
1270     */
1271    private void putU4(int i)
1272    {
1273      stream.append((char) (i >> 24)).append((char) (i >> 16));
1274      stream.append((char) (i >> 8)).append((char) i);
1275    }
1276
1277    /**
1278     * Put bytecode to load a constant integer on the stream. This only
1279     * needs to work for values less than Short.MAX_VALUE.
1280     *
1281     * @param i the int to add
1282     */
1283    private void putConst(int i)
1284    {
1285      if (i >= -1 && i <= 5)
1286        putU1(ICONST_0 + i);
1287      else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
1288        {
1289          putU1(BIPUSH);
1290          putU1(i);
1291        }
1292      else
1293        {
1294          putU1(SIPUSH);
1295          putU2(i);
1296        }
1297    }
1298
1299    /**
1300     * Put bytecode to load a given local variable on the stream.
1301     *
1302     * @param i the slot to load
1303     * @param type the base type of the load
1304     */
1305    private void putLoad(int i, Class type)
1306    {
1307      int offset = 0;
1308      if (type == long.class)
1309        offset = 1;
1310      else if (type == float.class)
1311        offset = 2;
1312      else if (type == double.class)
1313        offset = 3;
1314      else if (! type.isPrimitive())
1315        offset = 4;
1316      if (i < 4)
1317        putU1(ILOAD_0 + 4 * offset + i);
1318      else
1319        {
1320          putU1(ILOAD + offset);
1321          putU1(i);
1322        }
1323    }
1324
1325    /**
1326     * Given a primitive type, return its wrapper class name.
1327     *
1328     * @param clazz the primitive type (but not void.class)
1329     * @return the internal form of the wrapper class name
1330     */
1331    private String wrapper(Class clazz)
1332    {
1333      if (clazz == boolean.class)
1334        return "java/lang/Boolean";
1335      if (clazz == byte.class)
1336        return "java/lang/Byte";
1337      if (clazz == short.class)
1338        return "java/lang/Short";
1339      if (clazz == char.class)
1340        return "java/lang/Character";
1341      if (clazz == int.class)
1342        return "java/lang/Integer";
1343      if (clazz == long.class)
1344        return "java/lang/Long";
1345      if (clazz == float.class)
1346        return "java/lang/Float";
1347      if (clazz == double.class)
1348        return "java/lang/Double";
1349      // assert false;
1350      return null;
1351    }
1352
1353    /**
1354     * Returns the entry of this String in the Constant pool, adding it
1355     * if necessary.
1356     *
1357     * @param str the String to resolve
1358     * @return the index of the String in the constant pool
1359     */
1360    private char utf8Info(String str)
1361    {
1362      String utf8 = toUtf8(str);
1363      int len = utf8.length();
1364      return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
1365    }
1366
1367    /**
1368     * Returns the entry of the appropriate class info structure in the
1369     * Constant pool, adding it if necessary.
1370     *
1371     * @param name the class name, in internal form
1372     * @return the index of the ClassInfo in the constant pool
1373     */
1374    private char classInfo(String name)
1375    {
1376      char index = utf8Info(name);
1377      char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
1378      return poolIndex(new String(c));
1379    }