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 }