1 /* Proxy.java -- build a proxy class that implements reflected interfaces
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package java
.lang
.reflect
;
41 import gnu
.java
.lang
.CPStringBuilder
;
43 import gnu
.java
.lang
.reflect
.TypeSignature
;
45 import java
.io
.Serializable
;
46 import java
.security
.ProtectionDomain
;
47 import java
.util
.Arrays
;
48 import java
.util
.HashMap
;
49 import java
.util
.HashSet
;
50 import java
.util
.Iterator
;
55 * This class allows you to dynamically create an instance of any (or
56 * even multiple) interfaces by reflection, and decide at runtime
57 * how that instance will behave by giving it an appropriate
58 * {@link InvocationHandler}. Proxy classes serialize specially, so
59 * that the proxy object can be reused between VMs, without requiring
60 * a persistent copy of the generated class code.
63 * To create a proxy for some interface Foo:
66 * InvocationHandler handler = new MyInvocationHandler(...);
67 * Class proxyClass = Proxy.getProxyClass(
68 * Foo.class.getClassLoader(), new Class[] { Foo.class });
69 * Foo f = (Foo) proxyClass
70 * .getConstructor(new Class[] { InvocationHandler.class })
71 * .newInstance(new Object[] { handler });
75 * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
76 * new Class[] { Foo.class },
80 * <h3>Dynamic Proxy Classes</h3>
81 * A dynamic proxy class is created at runtime, and has the following
84 * <li>The class is <code>public</code> and <code>final</code>,
85 * and is neither <code>abstract</code> nor an inner class.</li>
86 * <li>The class has no canonical name (there is no formula you can use
87 * to determine or generate its name), but begins with the
88 * sequence "$Proxy". Abuse this knowledge at your own peril.
89 * (For now, '$' in user identifiers is legal, but it may not
90 * be that way forever. You weren't using '$' in your
91 * identifiers, were you?)</li>
92 * <li>The class extends Proxy, and explicitly implements all the
93 * interfaces specified at creation, in order (this is important
94 * for determining how method invocation is resolved). Note that
95 * a proxy class implements {@link Serializable}, at least
96 * implicitly, since Proxy does, but true serial behavior
97 * depends on using a serializable invocation handler as well.</li>
98 * <li>If at least one interface is non-public, the proxy class
99 * will be in the same package. Otherwise, the package is
100 * unspecified. This will work even if the package is sealed
101 * from user-generated classes, because Proxy classes are
102 * generated by a trusted source. Meanwhile, the proxy class
103 * belongs to the classloader you designated.</li>
104 * <li>Reflection works as expected: {@link Class#getInterfaces()} and
105 * {@link Class#getMethods()} work as they do on normal classes.</li>
106 * <li>The method {@link #isProxyClass(Class)} will distinguish between
107 * true proxy classes and user extensions of this class. It only
108 * returns true for classes created by {@link #getProxyClass}.</li>
109 * <li>The {@link ProtectionDomain} of a proxy class is the same as for
110 * bootstrap classes, such as Object or Proxy, since it is created by
111 * a trusted source. This protection domain will typically be granted
112 * {@link java.security.AllPermission}. But this is not a security
113 * risk, since there are adequate permissions on reflection, which is
114 * the only way to create an instance of the proxy class.</li>
115 * <li>The proxy class contains a single constructor, which takes as
116 * its only argument an {@link InvocationHandler}. The method
117 * {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
118 * is shorthand to do the necessary reflection.</li>
121 * <h3>Proxy Instances</h3>
122 * A proxy instance is an instance of a proxy class. It has the
123 * following properties, many of which follow from the properties of a
124 * proxy class listed above:
126 * <li>For a proxy class with Foo listed as one of its interfaces, the
127 * expression <code>proxy instanceof Foo</code> will return true,
128 * and the expression <code>(Foo) proxy</code> will succeed without
129 * a {@link ClassCastException}.</li>
130 * <li>Each proxy instance has an invocation handler, which can be
131 * accessed by {@link #getInvocationHandler(Object)}. Any call
132 * to an interface method, including {@link Object#hashCode()},
133 * {@link Object#equals(Object)}, or {@link Object#toString()},
134 * but excluding the public final methods of Object, will be
135 * encoded and passed to the {@link InvocationHandler#invoke}
136 * method of this handler.</li>
139 * <h3>Inheritance Issues</h3>
140 * A proxy class may inherit a method from more than one interface.
141 * The order in which interfaces are listed matters, because it determines
142 * which reflected {@link Method} object will be passed to the invocation
143 * handler. This means that the dynamically generated class cannot
144 * determine through which interface a method is being invoked.<p>
146 * In short, if a method is declared in Object (namely, hashCode,
147 * equals, or toString), then Object will be used; otherwise, the
148 * leftmost interface that inherits or declares a method will be used,
149 * even if it has a more permissive throws clause than what the proxy
150 * class is allowed. Thus, in the invocation handler, it is not always
151 * safe to assume that every class listed in the throws clause of the
152 * passed Method object can safely be thrown; fortunately, the Proxy
153 * instance is robust enough to wrap all illegal checked exceptions in
154 * {@link UndeclaredThrowableException}.
156 * @see InvocationHandler
157 * @see UndeclaredThrowableException
159 * @author Eric Blake (ebb9@email.byu.edu)
161 * @status updated to 1.5, except for the use of ProtectionDomain
163 public class Proxy
implements Serializable
166 * Compatible with JDK 1.3+.
168 private static final long serialVersionUID
= -2222568056686623797L;
171 * Map of ProxyType to proxy class.
173 * @XXX This prevents proxy classes from being garbage collected.
174 * java.util.WeakHashSet is not appropriate, because that collects the
175 * keys, but we are interested in collecting the elements.
177 private static final Map proxyClasses
= new HashMap();
180 * The invocation handler for this proxy instance. For Proxy, this
181 * field is unused, but it appears here in order to be serialized in all
184 * <em>NOTE</em>: This implementation is more secure for proxy classes
185 * than what Sun specifies. Sun does not require h to be immutable, but
186 * this means you could change h after the fact by reflection. However,
187 * by making h immutable, we may break non-proxy classes which extend
189 * @serial invocation handler associated with this proxy instance
191 protected InvocationHandler h
;
194 * Constructs a new Proxy from a subclass (usually a proxy class),
195 * with the specified invocation handler.
197 * <em>NOTE</em>: This throws a NullPointerException if you attempt
198 * to create a proxy instance with a null handler using reflection.
199 * This behavior is not yet specified by Sun; see Sun Bug 4487672.
201 * @param handler the invocation handler, may be null if the subclass
202 * is not a proxy class
203 * @throws NullPointerException if handler is null and this is a proxy
206 protected Proxy(InvocationHandler handler
)
208 if (handler
== null && isProxyClass(getClass()))
209 throw new NullPointerException("invalid handler");
214 * Returns the proxy {@link Class} for the given ClassLoader and array
215 * of interfaces, dynamically generating it if necessary.
217 * <p>There are several restrictions on this method, the violation of
218 * which will result in an IllegalArgumentException or
219 * NullPointerException:</p>
222 * <li>All objects in `interfaces' must represent distinct interfaces.
223 * Classes, primitive types, null, and duplicates are forbidden.</li>
224 * <li>The interfaces must be visible in the specified ClassLoader.
225 * In other words, for each interface i:
226 * <code>Class.forName(i.getName(), false, loader) == i</code>
228 * <li>All non-public interfaces (if any) must reside in the same
229 * package, or the proxy class would be non-instantiable. If
230 * there are no non-public interfaces, the package of the proxy
231 * class is unspecified.</li>
232 * <li>All interfaces must be compatible - if two declare a method
233 * with the same name and parameters, the return type must be
234 * the same and the throws clause of the proxy class will be
235 * the maximal subset of subclasses of the throws clauses for
236 * each method that is overridden.</li>
237 * <li>VM constraints limit the number of interfaces a proxy class
238 * may directly implement (however, the indirect inheritance
239 * of {@link Serializable} does not count against this limit).
240 * Even though most VMs can theoretically have 65535
241 * superinterfaces for a class, the actual limit is smaller
242 * because a class's constant pool is limited to 65535 entries,
243 * and not all entries can be interfaces.</li>
246 * <p>Note that different orders of interfaces produce distinct classes.</p>
248 * @param loader the class loader to define the proxy class in; null
249 * implies the bootstrap class loader
250 * @param interfaces the array of interfaces the proxy class implements,
251 * may be empty, but not null
252 * @return the Class object of the proxy class
253 * @throws IllegalArgumentException if the constraints above were
254 * violated, except for problems with null
255 * @throws NullPointerException if `interfaces' is null or contains
258 // synchronized so that we aren't trying to build the same class
259 // simultaneously in two threads
260 public static synchronized Class
<?
> getProxyClass(ClassLoader loader
,
261 Class
<?
>... interfaces
)
263 interfaces
= (Class
[]) interfaces
.clone();
264 ProxyType pt
= new ProxyType(loader
, interfaces
);
265 Class clazz
= (Class
) proxyClasses
.get(pt
);
268 if (VMProxy
.HAVE_NATIVE_GET_PROXY_CLASS
)
269 clazz
= VMProxy
.getProxyClass(loader
, interfaces
);
272 ProxyData data
= (VMProxy
.HAVE_NATIVE_GET_PROXY_DATA
273 ? VMProxy
.getProxyData(loader
, interfaces
)
274 : ProxyData
.getProxyData(pt
));
276 clazz
= (VMProxy
.HAVE_NATIVE_GENERATE_PROXY_CLASS
277 ? VMProxy
.generateProxyClass(loader
, data
)
278 : new ClassFactory(data
).generate(loader
));
281 Object check
= proxyClasses
.put(pt
, clazz
);
282 // assert check == null && clazz != null;
283 if (check
!= null || clazz
== null)
284 throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
290 * Combines several methods into one. This is equivalent to:
292 * Proxy.getProxyClass(loader, interfaces)
293 * .getConstructor(new Class[] {InvocationHandler.class})
294 * .newInstance(new Object[] {handler});
296 * except that it will not fail with the normal problems caused
297 * by reflection. It can still fail for the same reasons documented
298 * in getProxyClass, or if handler is null.
300 * @param loader the class loader to define the proxy class in; null
301 * implies the bootstrap class loader
302 * @param interfaces the array of interfaces the proxy class implements,
303 * may be empty, but not null
304 * @param handler the invocation handler, may not be null
305 * @return a proxy instance implementing the specified interfaces
306 * @throws IllegalArgumentException if the constraints for getProxyClass
307 * were violated, except for problems with null
308 * @throws NullPointerException if `interfaces' is null or contains
309 * a null entry, or if handler is null
310 * @see #getProxyClass(ClassLoader, Class[])
311 * @see Class#getConstructor(Class[])
312 * @see Constructor#newInstance(Object[])
314 public static Object
newProxyInstance(ClassLoader loader
,
315 Class
<?
>[] interfaces
,
316 InvocationHandler handler
)
320 // getProxyClass() and Proxy() throw the necessary exceptions
321 return getProxyClass(loader
, interfaces
)
322 .getConstructor(new Class
[] {InvocationHandler
.class})
323 .newInstance(new Object
[] {handler
});
325 catch (RuntimeException e
)
327 // Let IllegalArgumentException, NullPointerException escape.
328 // assert e instanceof IllegalArgumentException
329 // || e instanceof NullPointerException;
332 catch (InvocationTargetException e
)
334 // Let wrapped NullPointerException escape.
335 // assert e.getTargetException() instanceof NullPointerException
336 throw (NullPointerException
) e
.getCause();
340 // Covers InstantiationException, IllegalAccessException,
341 // NoSuchMethodException, none of which should be generated
342 // if the proxy class was generated correctly.
344 throw (Error
) new InternalError("Unexpected: " + e
).initCause(e
);
349 * Returns true if and only if the Class object is a dynamically created
350 * proxy class (created by <code>getProxyClass</code> or by the
351 * syntactic sugar of <code>newProxyInstance</code>).
353 * <p>This check is secure (in other words, it is not simply
354 * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
355 * be spoofed by non-proxy classes that extend Proxy.
357 * @param clazz the class to check, must not be null
358 * @return true if the class represents a proxy class
359 * @throws NullPointerException if clazz is null
361 // This is synchronized on the off chance that another thread is
362 // trying to add a class to the map at the same time we read it.
363 public static synchronized boolean isProxyClass(Class
<?
> clazz
)
365 if (! Proxy
.class.isAssignableFrom(clazz
))
367 // This is a linear search, even though we could do an O(1) search
368 // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
369 return proxyClasses
.containsValue(clazz
);
373 * Returns the invocation handler for the given proxy instance.<p>
375 * <em>NOTE</em>: We guarantee a non-null result if successful,
376 * but Sun allows the creation of a proxy instance with a null
377 * handler. See the comments for {@link #Proxy(InvocationHandler)}.
379 * @param proxy the proxy instance, must not be null
380 * @return the invocation handler, guaranteed non-null.
381 * @throws IllegalArgumentException if
382 * <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
383 * @throws NullPointerException if proxy is null
385 public static InvocationHandler
getInvocationHandler(Object proxy
)
387 if (! isProxyClass(proxy
.getClass()))
388 throw new IllegalArgumentException("not a proxy instance");
389 return ((Proxy
) proxy
).h
;
393 * Helper class for mapping unique ClassLoader and interface combinations
396 * @author Eric Blake (ebb9@email.byu.edu)
398 private static final class ProxyType
401 * Store the class loader (may be null)
403 final ClassLoader loader
;
406 * Store the interfaces (never null, all elements are interfaces)
408 final Class
[] interfaces
;
411 * Construct the helper object.
413 * @param loader the class loader to define the proxy class in; null
414 * implies the bootstrap class loader
415 * @param interfaces an array of interfaces
417 ProxyType(ClassLoader loader
, Class
[] interfaces
)
419 this.loader
= loader
;
420 this.interfaces
= interfaces
;
424 * Calculates the hash code.
426 * @return a combination of the classloader and interfaces hashcodes.
428 public int hashCode()
430 int hash
= loader
== null ?
0 : loader
.hashCode();
431 for (int i
= 0; i
< interfaces
.length
; i
++)
432 hash
= hash
* 31 + interfaces
[i
].hashCode();
437 * Calculates equality.
439 * @param other object to compare to
440 * @return true if it is a ProxyType with same data
442 public boolean equals(Object other
)
444 ProxyType pt
= (ProxyType
) other
;
445 if (loader
!= pt
.loader
|| interfaces
.length
!= pt
.interfaces
.length
)
447 for (int i
= 0; i
< interfaces
.length
; i
++)
448 if (interfaces
[i
] != pt
.interfaces
[i
])
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
459 * @author Eric Blake (ebb9@email.byu.edu)
461 private static final class ProxySignature
464 * The core signatures which all Proxy instances handle.
466 static final HashMap coreMethods
= new HashMap();
472 = new ProxySignature(Object
.class
474 new Class
[] {Object
.class}));
475 coreMethods
.put(sig
, sig
);
476 sig
= new ProxySignature(Object
.class.getMethod("hashCode"));
477 coreMethods
.put(sig
, sig
);
478 sig
= new ProxySignature(Object
.class.getMethod("toString"));
479 coreMethods
.put(sig
, sig
);
484 throw (Error
) new InternalError("Unexpected: " + e
).initCause(e
);
489 * The underlying Method object, never null
494 * The set of compatible thrown exceptions, may be empty
496 final Set exceptions
= new HashSet();
499 * Construct a signature
501 * @param method the Method this signature is based on, never null
503 ProxySignature(Method method
)
505 this.method
= method
;
506 Class
[] exc
= method
.getExceptionTypes();
510 // discard unchecked exceptions
511 if (Error
.class.isAssignableFrom(exc
[i
])
512 || RuntimeException
.class.isAssignableFrom(exc
[i
]))
514 exceptions
.add(exc
[i
]);
519 * Given a method, make sure it's return type is identical
520 * to this, and adjust this signature's throws clause appropriately
522 * @param other the signature to merge in
523 * @throws IllegalArgumentException if the return types conflict
525 void checkCompatibility(ProxySignature other
)
527 if (method
.getReturnType() != other
.method
.getReturnType())
528 throw new IllegalArgumentException("incompatible return types: "
529 + method
+ ", " + other
.method
);
531 // if you can think of a more efficient way than this O(n^2) search,
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();
541 Class c1
= (Class
) itr
.next();
542 Iterator itr2
= other
.exceptions
.iterator();
546 Class c2
= (Class
) itr2
.next();
547 if (c2
.isAssignableFrom(c1
))
549 if (c1
.isAssignableFrom(c2
))
554 itr
= exceptions
.iterator();
562 itr
= other
.exceptions
.iterator();
569 exceptions
.addAll(other
.exceptions
);
573 * Calculates the hash code.
575 * @return a combination of name and parameter types
577 public int hashCode()
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();
587 * Calculates equality.
589 * @param other object to compare to
590 * @return true if it is a ProxySignature with same data
592 public boolean equals(Object other
)
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
)
600 int i
= types1
.length
;
602 if (types1
[i
] != types2
[i
])
606 } // class ProxySignature
609 * A flat representation of all data needed to generate bytecode/instantiate
610 * a proxy class. This is basically a struct.
612 * @author Eric Blake (ebb9@email.byu.edu)
614 static final class ProxyData
617 * The package this class is in <b>including the trailing dot</b>
618 * or an empty string for the unnamed (aka default) package.
623 * The interfaces this class implements. Non-null, but possibly empty.
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).
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
644 Class
[][] exceptions
;
649 private static int count
;
652 * The id of this proxy class
654 final int id
= count
++;
657 * Construct a ProxyData with uninitialized data members.
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.
670 private static String
getPackage(Class k
)
672 String name
= k
.getName();
673 int idx
= name
.lastIndexOf('.');
674 return name
.substring(0, idx
+ 1);
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
682 * @param pt the ProxyType to convert to ProxyData
683 * @return the flattened, verified ProxyData structure for use in
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
689 static ProxyData
getProxyData(ProxyType pt
)
691 Map method_set
= (Map
) ProxySignature
.coreMethods
.clone();
692 boolean in_package
= false; // true if we encounter non-public interface
694 ProxyData data
= new ProxyData();
695 data
.interfaces
= pt
.interfaces
;
697 // if interfaces is too large, we croak later on when the constant
699 int i
= data
.interfaces
.length
;
702 Class inter
= data
.interfaces
[i
];
703 if (! inter
.isInterface())
704 throw new IllegalArgumentException("not an interface: " + inter
);
707 if (Class
.forName(inter
.getName(), false, pt
.loader
) != inter
)
708 throw new IllegalArgumentException("not accessible in "
709 + "classloader: " + inter
);
711 catch (ClassNotFoundException e
)
713 throw new IllegalArgumentException("not accessible in "
714 + "classloader: " + inter
);
716 if (! Modifier
.isPublic(inter
.getModifiers()))
719 String p
= getPackage(inter
);
720 if (! data
.pack
.equals(p
))
721 throw new IllegalArgumentException("non-public interfaces "
728 data
.pack
= getPackage(inter
);
730 for (int j
= i
-1; j
>= 0; j
--)
731 if (data
.interfaces
[j
] == inter
)
732 throw new IllegalArgumentException("duplicate interface: "
734 Method
[] methods
= inter
.getMethods();
735 int j
= methods
.length
;
738 if (isCoreObjectMethod(methods
[j
]))
740 // In the case of an attempt to redefine a public non-final
741 // method of Object, we must skip it
744 ProxySignature sig
= new ProxySignature(methods
[j
]);
745 ProxySignature old
= (ProxySignature
) method_set
.put(sig
, sig
);
747 sig
.checkCompatibility(old
);
751 i
= method_set
.size();
752 data
.methods
= new Method
[i
];
753 data
.exceptions
= new Class
[i
][];
754 Iterator itr
= method_set
.values().iterator();
757 ProxySignature sig
= (ProxySignature
) itr
.next();
758 data
.methods
[i
] = sig
.method
;
759 data
.exceptions
[i
] = (Class
[]) sig
.exceptions
760 .toArray(new Class
[sig
.exceptions
.size()]);
766 * Checks whether the method is similar to a public non-final method of
767 * Object or not (i.e. with the same name and parameter types). Note that we
768 * can't rely, directly or indirectly (via Collection.contains) on
769 * Method.equals as it would also check the declaring class, what we do not
770 * want. We only want to check that the given method have the same signature
771 * as a core method (same name and parameter types)
773 * @param method the method to check
774 * @return whether the method has the same name and parameter types as
775 * Object.equals, Object.hashCode or Object.toString
776 * @see java.lang.Object#equals(Object)
777 * @see java.lang.Object#hashCode()
778 * @see java.lang.Object#toString()
780 private static boolean isCoreObjectMethod(Method method
)
782 String methodName
= method
.getName();
783 if (methodName
.equals("equals"))
785 return Arrays
.equals(method
.getParameterTypes(),
786 new Class
[] { Object
.class });
788 if (methodName
.equals("hashCode"))
790 return method
.getParameterTypes().length
== 0;
792 if (methodName
.equals("toString"))
794 return method
.getParameterTypes().length
== 0;
802 * Does all the work of building a class. By making this a nested class,
803 * this code is not loaded in memory if the VM has a native
804 * implementation instead.
806 * @author Eric Blake (ebb9@email.byu.edu)
808 private static final class ClassFactory
810 /** Constants for assisting the compilation */
811 private static final byte FIELD
= 1;
812 private static final byte METHOD
= 2;
813 private static final byte INTERFACE
= 3;
814 private static final String CTOR_SIG
815 = "(Ljava/lang/reflect/InvocationHandler;)V";
816 private static final String INVOKE_SIG
= "(Ljava/lang/Object;"
817 + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
819 /** Bytecodes for insertion in the class definition byte[] */
820 private static final char ACONST_NULL
= 1;
821 private static final char ICONST_0
= 3;
822 private static final char BIPUSH
= 16;
823 private static final char SIPUSH
= 17;
824 private static final char ILOAD
= 21;
825 private static final char ILOAD_0
= 26;
826 private static final char ALOAD_0
= 42;
827 private static final char ALOAD_1
= 43;
828 private static final char AALOAD
= 50;
829 private static final char AASTORE
= 83;
830 private static final char DUP
= 89;
831 private static final char DUP_X1
= 90;
832 private static final char SWAP
= 95;
833 private static final char IRETURN
= 172;
834 private static final char LRETURN
= 173;
835 private static final char FRETURN
= 174;
836 private static final char DRETURN
= 175;
837 private static final char ARETURN
= 176;
838 private static final char RETURN
= 177;
839 private static final char GETSTATIC
= 178;
840 private static final char GETFIELD
= 180;
841 private static final char INVOKEVIRTUAL
= 182;
842 private static final char INVOKESPECIAL
= 183;
843 private static final char INVOKEINTERFACE
= 185;
844 private static final char NEW
= 187;
845 private static final char ANEWARRAY
= 189;
846 private static final char ATHROW
= 191;
847 private static final char CHECKCAST
= 192;
849 // Implementation note: we use StringBuffers to hold the byte data, since
850 // they automatically grow. However, we only use the low 8 bits of
851 // every char in the array, so we are using twice the necessary memory
852 // for the ease StringBuffer provides.
854 /** The constant pool. */
855 private final StringBuffer pool
= new StringBuffer();
856 /** The rest of the class data. */
857 private final StringBuffer stream
= new StringBuffer();
859 /** Map of strings to byte sequences, to minimize size of pool. */
860 private final Map poolEntries
= new HashMap();
862 /** The VM name of this proxy class. */
863 private final String qualName
;
866 * The Method objects the proxy class refers to when calling the
867 * invocation handler.
869 private final Method
[] methods
;
872 * Initializes the buffers with the bytecode contents for a proxy class.
874 * @param data the remainder of the class data
875 * @throws IllegalArgumentException if anything else goes wrong this
876 * late in the game; as far as I can tell, this will only happen
877 * if the constant pool overflows, which is possible even when
878 * the user doesn't exceed the 65535 interface limit
880 ClassFactory(ProxyData data
)
882 methods
= data
.methods
;
884 // magic = 0xcafebabe
886 // major_version = 46
887 // constant_pool_count: place-holder for now
888 pool
.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
889 // constant_pool[], filled in as we go
892 putU2(Modifier
.SUPER
| Modifier
.FINAL
| Modifier
.PUBLIC
);
894 qualName
= (data
.pack
+ "$Proxy" + data
.id
);
895 putU2(classInfo(TypeSignature
.getEncodingOfClass(qualName
, false)));
897 putU2(classInfo("java/lang/reflect/Proxy"));
900 putU2(data
.interfaces
.length
);
902 for (int i
= 0; i
< data
.interfaces
.length
; i
++)
903 putU2(classInfo(data
.interfaces
[i
]));
905 // Recall that Proxy classes serialize specially, so we do not need
906 // to worry about a <clinit> method for this field. Instead, we
907 // just assign it by reflection after the class is successfully loaded.
908 // fields_count - private static Method[] m;
912 putU2(Modifier
.PRIVATE
| Modifier
.STATIC
);
914 putU2(utf8Info("m"));
915 // m.descriptor_index
916 putU2(utf8Info("[Ljava/lang/reflect/Method;"));
917 // m.attributes_count
921 // methods_count - # handler methods, plus <init>
922 putU2(methods
.length
+ 1);
924 // <init>.access_flags
925 putU2(Modifier
.PUBLIC
);
927 putU2(utf8Info("<init>"));
928 // <init>.descriptor_index
929 putU2(utf8Info(CTOR_SIG
));
930 // <init>.attributes_count - only Code is needed
932 // <init>.Code.attribute_name_index
933 putU2(utf8Info("Code"));
934 // <init>.Code.attribute_length = 18
936 // $Proxynn(InvocationHandler h) { super(h); }
937 // <init>.Code.max_stack = 2
938 // <init>.Code.max_locals = 2
939 // <init>.Code.code_length = 6
940 // <init>.Code.code[]
941 stream
.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0
+ ALOAD_1
943 putU2(refInfo(METHOD
, "java/lang/reflect/Proxy", "<init>", CTOR_SIG
));
944 // <init>.Code.exception_table_length = 0
945 // <init>.Code.exception_table[]
946 // <init>.Code.attributes_count = 0
947 // <init>.Code.attributes[]
948 stream
.append(RETURN
+ "\0\0\0\0");
950 for (int i
= methods
.length
- 1; i
>= 0; i
--)
951 emitMethod(i
, data
.exceptions
[i
]);
955 // attributes[] - empty; omit SourceFile attribute
956 // XXX should we mark this with a Synthetic attribute?
960 * Produce the bytecode for a single method.
962 * @param i the index of the method we are building
963 * @param e the exceptions possible for the method
965 private void emitMethod(int i
, Class
[] e
)
967 // First, we precalculate the method length and other information.
969 Method m
= methods
[i
];
970 Class
[] paramtypes
= m
.getParameterTypes();
971 int wrap_overhead
= 0; // max words taken by wrapped primitive
972 int param_count
= 1; // 1 for this
973 int code_length
= 16; // aload_0, getfield, aload_0, getstatic, const,
974 // aaload, const/aconst_null, invokeinterface
977 if (i
> Byte
.MAX_VALUE
)
978 code_length
+= 2; // sipush
980 code_length
++; // bipush
982 if (paramtypes
.length
> 0)
984 code_length
+= 3; // anewarray
985 if (paramtypes
.length
> Byte
.MAX_VALUE
)
986 code_length
+= 2; // sipush
987 else if (paramtypes
.length
> 5)
988 code_length
++; // bipush
989 for (int j
= 0; j
< paramtypes
.length
; j
++)
991 code_length
+= 4; // dup, const, load, store
992 Class type
= paramtypes
[j
];
995 if (j
> Byte
.MAX_VALUE
)
996 code_length
+= 2; // sipush
998 code_length
++; // bipush
1000 if (param_count
>= 4)
1001 code_length
++; // 2-byte load
1003 if (type
.isPrimitive())
1005 code_length
+= 7; // new, dup, invokespecial
1006 if (type
== long.class || type
== double.class)
1011 else if (wrap_overhead
< 2)
1016 int end_pc
= code_length
;
1017 Class ret_type
= m
.getReturnType();
1018 if (ret_type
== void.class)
1019 code_length
++; // return
1020 else if (ret_type
.isPrimitive())
1021 code_length
+= 7; // cast, invokevirtual, return
1023 code_length
+= 4; // cast, return
1024 int exception_count
= 0;
1025 boolean throws_throwable
= false;
1026 for (int j
= 0; j
< e
.length
; j
++)
1027 if (e
[j
] == Throwable
.class)
1029 throws_throwable
= true;
1032 if (! throws_throwable
)
1034 exception_count
= e
.length
+ 3; // Throwable, Error, RuntimeException
1035 code_length
+= 9; // new, dup_x1, swap, invokespecial, athrow
1037 int handler_pc
= code_length
- 1;
1038 CPStringBuilder signature
= new CPStringBuilder("(");
1039 for (int j
= 0; j
< paramtypes
.length
; j
++)
1040 signature
.append(TypeSignature
.getEncodingOfClass(paramtypes
[j
]));
1041 signature
.append(")").append(TypeSignature
.getEncodingOfClass(ret_type
));
1043 // Now we have enough information to emit the method.
1045 // handler.access_flags
1046 putU2(Modifier
.PUBLIC
| Modifier
.FINAL
);
1047 // handler.name_index
1048 putU2(utf8Info(m
.getName()));
1049 // handler.descriptor_index
1050 putU2(utf8Info(signature
.toString()));
1051 // handler.attributes_count - Code is necessary, Exceptions possible
1052 putU2(e
.length
> 0 ?
2 : 1);
1054 // handler.Code.info:
1055 // type name(args) {
1057 // return (type) h.invoke(this, methods[i], new Object[] {args});
1058 // } catch (<declared Exceptions> e) {
1060 // } catch (Throwable t) {
1061 // throw new UndeclaredThrowableException(t);
1065 // if arg_n is primitive, wrap it
1066 // if method throws Throwable, try-catch is not needed
1067 // if method returns void, return statement not needed
1068 // if method returns primitive, unwrap it
1069 // save space by sharing code for all the declared handlers
1071 // handler.Code.attribute_name_index
1072 putU2(utf8Info("Code"));
1073 // handler.Code.attribute_length
1074 putU4(12 + code_length
+ 8 * exception_count
);
1075 // handler.Code.max_stack
1076 putU2(param_count
== 1 ?
4 : 7 + wrap_overhead
);
1077 // handler.Code.max_locals
1079 // handler.Code.code_length
1081 // handler.Code.code[]
1084 putU2(refInfo(FIELD
, "java/lang/reflect/Proxy", "h",
1085 "Ljava/lang/reflect/InvocationHandler;"));
1088 putU2(refInfo(FIELD
, TypeSignature
.getEncodingOfClass(qualName
, false),
1089 "m", "[Ljava/lang/reflect/Method;"));
1092 if (paramtypes
.length
> 0)
1094 putConst(paramtypes
.length
);
1096 putU2(classInfo("java/lang/Object"));
1098 for (int j
= 0; j
< paramtypes
.length
; j
++, param_count
++)
1102 if (paramtypes
[j
].isPrimitive())
1105 putU2(classInfo(wrapper(paramtypes
[j
])));
1108 putLoad(param_count
, paramtypes
[j
]);
1109 if (paramtypes
[j
].isPrimitive())
1111 putU1(INVOKESPECIAL
);
1112 putU2(refInfo(METHOD
, wrapper(paramtypes
[j
]), "<init>",
1113 '(' + (TypeSignature
1114 .getEncodingOfClass(paramtypes
[j
])
1116 if (paramtypes
[j
] == long.class
1117 || paramtypes
[j
] == double.class)
1125 putU1(INVOKEINTERFACE
);
1126 putU2(refInfo(INTERFACE
, "java/lang/reflect/InvocationHandler",
1127 "invoke", INVOKE_SIG
));
1128 putU1(4); // InvocationHandler, this, Method, Object[]
1130 if (ret_type
== void.class)
1132 else if (ret_type
.isPrimitive())
1135 putU2(classInfo(wrapper(ret_type
)));
1136 putU1(INVOKEVIRTUAL
);
1137 putU2(refInfo(METHOD
, wrapper(ret_type
),
1138 ret_type
.getName() + "Value",
1139 "()" + TypeSignature
.getEncodingOfClass(ret_type
)));
1140 if (ret_type
== long.class)
1142 else if (ret_type
== float.class)
1144 else if (ret_type
== double.class)
1152 putU2(classInfo(ret_type
));
1155 if (! throws_throwable
)
1158 putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
1161 putU1(INVOKESPECIAL
);
1162 putU2(refInfo(METHOD
,
1163 "java/lang/reflect/UndeclaredThrowableException",
1164 "<init>", "(Ljava/lang/Throwable;)V"));
1168 // handler.Code.exception_table_length
1169 putU2(exception_count
);
1170 // handler.Code.exception_table[]
1171 if (! throws_throwable
)
1173 // handler.Code.exception_table.start_pc
1175 // handler.Code.exception_table.end_pc
1177 // handler.Code.exception_table.handler_pc
1179 // handler.Code.exception_table.catch_type
1180 putU2(classInfo("java/lang/Error"));
1181 // handler.Code.exception_table.start_pc
1183 // handler.Code.exception_table.end_pc
1185 // handler.Code.exception_table.handler_pc
1187 // handler.Code.exception_table.catch_type
1188 putU2(classInfo("java/lang/RuntimeException"));
1189 for (int j
= 0; j
< e
.length
; j
++)
1191 // handler.Code.exception_table.start_pc
1193 // handler.Code.exception_table.end_pc
1195 // handler.Code.exception_table.handler_pc
1197 // handler.Code.exception_table.catch_type
1198 putU2(classInfo(e
[j
]));
1200 // handler.Code.exception_table.start_pc
1202 // handler.Code.exception_table.end_pc
1204 // handler.Code.exception_table.handler_pc -
1205 // -8 for undeclared handler, which falls thru to normal one
1206 putU2(handler_pc
- 8);
1207 // handler.Code.exception_table.catch_type
1210 // handler.Code.attributes_count
1212 // handler.Code.attributes[]
1216 // handler.Exceptions.attribute_name_index
1217 putU2(utf8Info("Exceptions"));
1218 // handler.Exceptions.attribute_length
1219 putU4(2 * e
.length
+ 2);
1220 // handler.Exceptions.number_of_exceptions
1222 // handler.Exceptions.exception_index_table[]
1223 for (int j
= 0; j
< e
.length
; j
++)
1224 putU2(classInfo(e
[j
]));
1229 * Creates the Class object that corresponds to the bytecode buffers
1230 * built when this object was constructed.
1232 * @param loader the class loader to define the proxy class in; null
1233 * implies the bootstrap class loader
1234 * @return the proxy class Class object
1236 Class
generate(ClassLoader loader
)
1238 byte[] bytecode
= new byte[pool
.length() + stream
.length()];
1239 // More efficient to bypass calling charAt() repetitively.
1240 char[] c
= pool
.toString().toCharArray();
1243 bytecode
[i
] = (byte) c
[i
];
1244 c
= stream
.toString().toCharArray();
1246 int j
= bytecode
.length
;
1248 bytecode
[--j
] = (byte) c
[--i
];
1250 // Patch the constant pool size, which we left at 0 earlier.
1251 int count
= poolEntries
.size() + 1;
1252 bytecode
[8] = (byte) (count
>> 8);
1253 bytecode
[9] = (byte) count
;
1257 Class vmClassLoader
= Class
.forName("java.lang.VMClassLoader");
1258 Class
[] types
= {ClassLoader
.class, String
.class,
1259 byte[].class, int.class, int.class,
1260 ProtectionDomain
.class };
1261 Method m
= vmClassLoader
.getDeclaredMethod("defineClass", types
);
1262 // We can bypass the security check of setAccessible(true), since
1263 // we're in the same package.
1266 Object
[] args
= {loader
, qualName
, bytecode
, Integer
.valueOf(0),
1267 Integer
.valueOf(bytecode
.length
),
1268 Object
.class.getProtectionDomain() };
1269 Class clazz
= (Class
) m
.invoke(null, args
);
1271 // Finally, initialize the m field of the proxy class, before
1273 Field f
= clazz
.getDeclaredField("m");
1275 // we can share the array, because it is not publicized
1276 f
.set(null, methods
);
1283 throw (Error
) new InternalError("Unexpected: " + e
).initCause(e
);
1288 * Put a single byte on the stream.
1290 * @param i the information to add (only lowest 8 bits are used)
1292 private void putU1(int i
)
1294 stream
.append((char) i
);
1298 * Put two bytes on the stream.
1300 * @param i the information to add (only lowest 16 bits are used)
1302 private void putU2(int i
)
1304 stream
.append((char) (i
>> 8)).append((char) i
);
1308 * Put four bytes on the stream.
1310 * @param i the information to add (treated as unsigned)
1312 private void putU4(int i
)
1314 stream
.append((char) (i
>> 24)).append((char) (i
>> 16));
1315 stream
.append((char) (i
>> 8)).append((char) i
);
1319 * Put bytecode to load a constant integer on the stream. This only
1320 * needs to work for values less than Short.MAX_VALUE.
1322 * @param i the int to add
1324 private void putConst(int i
)
1326 if (i
>= -1 && i
<= 5)
1327 putU1(ICONST_0
+ i
);
1328 else if (i
>= Byte
.MIN_VALUE
&& i
<= Byte
.MAX_VALUE
)
1341 * Put bytecode to load a given local variable on the stream.
1343 * @param i the slot to load
1344 * @param type the base type of the load
1346 private void putLoad(int i
, Class type
)
1349 if (type
== long.class)
1351 else if (type
== float.class)
1353 else if (type
== double.class)
1355 else if (! type
.isPrimitive())
1358 putU1(ILOAD_0
+ 4 * offset
+ i
);
1361 putU1(ILOAD
+ offset
);
1367 * Given a primitive type, return its wrapper class name.
1369 * @param clazz the primitive type (but not void.class)
1370 * @return the internal form of the wrapper class name
1372 private String
wrapper(Class clazz
)
1374 if (clazz
== boolean.class)
1375 return "java/lang/Boolean";
1376 if (clazz
== byte.class)
1377 return "java/lang/Byte";
1378 if (clazz
== short.class)
1379 return "java/lang/Short";
1380 if (clazz
== char.class)
1381 return "java/lang/Character";
1382 if (clazz
== int.class)
1383 return "java/lang/Integer";
1384 if (clazz
== long.class)
1385 return "java/lang/Long";
1386 if (clazz
== float.class)
1387 return "java/lang/Float";
1388 if (clazz
== double.class)
1389 return "java/lang/Double";
1395 * Returns the entry of this String in the Constant pool, adding it
1398 * @param str the String to resolve
1399 * @return the index of the String in the constant pool
1401 private char utf8Info(String str
)
1403 String utf8
= toUtf8(str
);
1404 int len
= utf8
.length();
1405 return poolIndex("\1" + (char) (len
>> 8) + (char) (len
& 0xff) + utf8
);
1409 * Returns the entry of the appropriate class info structure in the
1410 * Constant pool, adding it if necessary.
1412 * @param name the class name, in internal form
1413 * @return the index of the ClassInfo in the constant pool
1415 private char classInfo(String name
)
1417 char index
= utf8Info(name
);
1418 char[] c
= {7, (char) (index
>> 8), (char) (index
& 0xff)};
1419 return poolIndex(new String(c
));
1423 * Returns the entry of the appropriate class info structure in the
1424 * Constant pool, adding it if necessary.
1426 * @param clazz the class type
1427 * @return the index of the ClassInfo in the constant pool
1429 private char classInfo(Class clazz
)
1431 return classInfo(TypeSignature
.getEncodingOfClass(clazz
.getName(),
1436 * Returns the entry of the appropriate fieldref, methodref, or
1437 * interfacemethodref info structure in the Constant pool, adding it
1440 * @param structure FIELD, METHOD, or INTERFACE
1441 * @param clazz the class name, in internal form
1442 * @param name the simple reference name
1443 * @param type the type of the reference
1444 * @return the index of the appropriate Info structure in the constant pool
1446 private char refInfo(byte structure
, String clazz
, String name
,
1449 char cindex
= classInfo(clazz
);
1450 char ntindex
= nameAndTypeInfo(name
, type
);
1451 // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
1452 char[] c
= {(char) (structure
+ 8),
1453 (char) (cindex
>> 8), (char) (cindex
& 0xff),
1454 (char) (ntindex
>> 8), (char) (ntindex
& 0xff)};
1455 return poolIndex(new String(c
));
1459 * Returns the entry of the appropriate nameAndTyperef info structure
1460 * in the Constant pool, adding it if necessary.
1462 * @param name the simple name
1463 * @param type the reference type
1464 * @return the index of the NameAndTypeInfo structure in the constant pool
1466 private char nameAndTypeInfo(String name
, String type
)
1468 char nindex
= utf8Info(name
);
1469 char tindex
= utf8Info(type
);
1470 char[] c
= {12, (char) (nindex
>> 8), (char) (nindex
& 0xff),
1471 (char) (tindex
>> 8), (char) (tindex
& 0xff)};
1472 return poolIndex(new String(c
));
1476 * Converts a regular string to a UTF8 string, where the upper byte
1477 * of every char is 0, and '\\u0000' is not in the string. This is
1478 * basically to use a String as a fancy byte[], and while it is less
1479 * efficient in memory use, it is easier for hashing.
1481 * @param str the original, in straight unicode
1482 * @return a modified string, in UTF8 format in the low bytes
1484 private String
toUtf8(String str
)
1486 final char[] ca
= str
.toCharArray();
1487 final int len
= ca
.length
;
1489 // Avoid object creation, if str is already fits UTF8.
1491 for (i
= 0; i
< len
; i
++)
1492 if (ca
[i
] == 0 || ca
[i
] > '\u007f')
1497 final CPStringBuilder sb
= new CPStringBuilder(str
);
1499 for ( ; i
< len
; i
++)
1501 final char c
= ca
[i
];
1502 if (c
> 0 && c
<= '\u007f')
1504 else if (c
<= '\u07ff') // includes '\0'
1506 sb
.append((char) (0xc0 | (c
>> 6)));
1507 sb
.append((char) (0x80 | (c
& 0x6f)));
1511 sb
.append((char) (0xe0 | (c
>> 12)));
1512 sb
.append((char) (0x80 | ((c
>> 6) & 0x6f)));
1513 sb
.append((char) (0x80 | (c
& 0x6f)));
1516 return sb
.toString();
1520 * Returns the location of a byte sequence (conveniently wrapped in
1521 * a String with all characters between \u0001 and \u00ff inclusive)
1522 * in the constant pool, adding it if necessary.
1524 * @param sequence the byte sequence to look for
1525 * @return the index of the sequence
1526 * @throws IllegalArgumentException if this would make the constant
1529 private char poolIndex(String sequence
)
1531 Integer i
= (Integer
) poolEntries
.get(sequence
);
1534 // pool starts at index 1
1535 int size
= poolEntries
.size() + 1;
1537 throw new IllegalArgumentException("exceeds VM limitations");
1538 i
= Integer
.valueOf(size
);
1539 poolEntries
.put(sequence
, i
);
1540 pool
.append(sequence
);
1542 return (char) i
.intValue();
1544 } // class ClassFactory