8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.reflect;
27
28 import java.lang.ref.Reference;
29 import java.lang.ref.WeakReference;
30 import java.security.AccessController;
31 import java.security.PrivilegedAction;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.List;
39 import java.util.WeakHashMap;
40 import sun.misc.ProxyGenerator;
41 import sun.misc.VM;
42 import sun.reflect.CallerSensitive;
43 import sun.reflect.Reflection;
44 import sun.reflect.misc.ReflectUtil;
45 import sun.security.util.SecurityConstants;
46
47 /**
48 * {@code Proxy} provides static methods for creating dynamic proxy
49 * classes and instances, and it is also the superclass of all
50 * dynamic proxy classes created by those methods.
51 *
52 * <p>To create a proxy for some interface {@code Foo}:
53 * <pre>
54 * InvocationHandler handler = new MyInvocationHandler(...);
55 * Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
56 * Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
57 * newInstance(handler);
58 * </pre>
59 * or more simply:
215 * types in the {@code throws} clause of the method in <i>all</i> of
216 * the proxy interfaces that it can be invoked through. If the
217 * {@code invoke} method throws a checked exception that is not
218 * assignable to any of the exception types declared by the method in one
219 * of the proxy interfaces that it can be invoked through, then an
220 * unchecked {@code UndeclaredThrowableException} will be thrown by
221 * the invocation on the proxy instance. This restriction means that not
222 * all of the exception types returned by invoking
223 * {@code getExceptionTypes} on the {@code Method} object
224 * passed to the {@code invoke} method can necessarily be thrown
225 * successfully by the {@code invoke} method.
226 *
227 * @author Peter Jones
228 * @see InvocationHandler
229 * @since 1.3
230 */
231 public class Proxy implements java.io.Serializable {
232
233 private static final long serialVersionUID = -2222568056686623797L;
234
235 /** prefix for all proxy class names */
236 private final static String proxyClassNamePrefix = "$Proxy";
237
238 /** parameter types of a proxy class constructor */
239 private final static Class[] constructorParams =
240 { InvocationHandler.class };
241
242 /** maps a class loader to the proxy class cache for that loader */
243 private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
244 = new WeakHashMap<>();
245
246 /** marks that a particular proxy class is currently being generated */
247 private static Object pendingGenerationMarker = new Object();
248
249 /** next number to use for generation of unique proxy class names */
250 private static long nextUniqueNumber = 0;
251 private static Object nextUniqueNumberLock = new Object();
252
253 /** set of all generated proxy classes, for isProxyClass implementation */
254 private static Map<Class<?>, Void> proxyClasses =
255 Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
256
257 /**
258 * the invocation handler for this proxy instance.
259 * @serial
260 */
261 protected InvocationHandler h;
262
263 /**
264 * Prohibits instantiation.
265 */
266 private Proxy() {
267 }
268
269 /**
270 * Constructs a new {@code Proxy} instance from a subclass
271 * (typically, a dynamic proxy class) with the specified value
272 * for its invocation handler.
273 *
274 * @param h the invocation handler for this proxy instance
275 */
406 SecurityManager sm = System.getSecurityManager();
407 if (sm != null) {
408 ClassLoader ccl = caller.getClassLoader();
409 if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
410 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
411 }
412 ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
413 }
414 }
415
416 /**
417 * Generate a proxy class. Must call the checkProxyAccess method
418 * to perform permission checks before calling this.
419 */
420 private static Class<?> getProxyClass0(ClassLoader loader,
421 Class<?>... interfaces) {
422 if (interfaces.length > 65535) {
423 throw new IllegalArgumentException("interface limit exceeded");
424 }
425
426 Class<?> proxyClass = null;
427
428 /* collect interface names to use as key for proxy class cache */
429 String[] interfaceNames = new String[interfaces.length];
430
431 // for detecting duplicates
432 Set<Class<?>> interfaceSet = new HashSet<>();
433
434 for (int i = 0; i < interfaces.length; i++) {
435 /*
436 * Verify that the class loader resolves the name of this
437 * interface to the same Class object.
438 */
439 String interfaceName = interfaces[i].getName();
440 Class<?> interfaceClass = null;
441 try {
442 interfaceClass = Class.forName(interfaceName, false, loader);
443 } catch (ClassNotFoundException e) {
444 }
445 if (interfaceClass != interfaces[i]) {
446 throw new IllegalArgumentException(
447 interfaces[i] + " is not visible from class loader");
448 }
449
450 /*
451 * Verify that the Class object actually represents an
452 * interface.
453 */
454 if (!interfaceClass.isInterface()) {
455 throw new IllegalArgumentException(
456 interfaceClass.getName() + " is not an interface");
457 }
458
459 /*
460 * Verify that this interface is not a duplicate.
461 */
462 if (interfaceSet.contains(interfaceClass)) {
463 throw new IllegalArgumentException(
464 "repeated interface: " + interfaceClass.getName());
465 }
466 interfaceSet.add(interfaceClass);
467
468 interfaceNames[i] = interfaceName;
469 }
470
471 /*
472 * Using string representations of the proxy interfaces as
473 * keys in the proxy class cache (instead of their Class
474 * objects) is sufficient because we require the proxy
475 * interfaces to be resolvable by name through the supplied
476 * class loader, and it has the advantage that using a string
477 * representation of a class makes for an implicit weak
478 * reference to the class.
479 */
480 List<String> key = Arrays.asList(interfaceNames);
481
482 /*
483 * Find or create the proxy class cache for the class loader.
484 */
485 Map<List<String>, Object> cache;
486 synchronized (loaderToCache) {
487 cache = loaderToCache.get(loader);
488 if (cache == null) {
489 cache = new HashMap<>();
490 loaderToCache.put(loader, cache);
491 }
492 /*
493 * This mapping will remain valid for the duration of this
494 * method, without further synchronization, because the mapping
495 * will only be removed if the class loader becomes unreachable.
496 */
497 }
498
499 /*
500 * Look up the list of interfaces in the proxy class cache using
501 * the key. This lookup will result in one of three possible
502 * kinds of values:
503 * null, if there is currently no proxy class for the list of
504 * interfaces in the class loader,
505 * the pendingGenerationMarker object, if a proxy class for the
506 * list of interfaces is currently being generated,
507 * or a weak reference to a Class object, if a proxy class for
508 * the list of interfaces has already been generated.
509 */
510 synchronized (cache) {
511 /*
512 * Note that we need not worry about reaping the cache for
513 * entries with cleared weak references because if a proxy class
514 * has been garbage collected, its class loader will have been
515 * garbage collected as well, so the entire cache will be reaped
516 * from the loaderToCache map.
517 */
518 do {
519 Object value = cache.get(key);
520 if (value instanceof Reference) {
521 proxyClass = (Class<?>) ((Reference) value).get();
522 }
523 if (proxyClass != null) {
524 // proxy class already generated: return it
525 return proxyClass;
526 } else if (value == pendingGenerationMarker) {
527 // proxy class being generated: wait for it
528 try {
529 cache.wait();
530 } catch (InterruptedException e) {
531 /*
532 * The class generation that we are waiting for should
533 * take a small, bounded time, so we can safely ignore
534 * thread interrupts here.
535 */
536 }
537 continue;
538 } else {
539 /*
540 * No proxy class for this list of interfaces has been
541 * generated or is being generated, so we will go and
542 * generate it now. Mark it as pending generation.
543 */
544 cache.put(key, pendingGenerationMarker);
545 break;
546 }
547 } while (true);
548 }
549
550 try {
551 String proxyPkg = null; // package to define proxy class in
552 int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
553
554 /*
555 * Record the package of a non-public proxy interface so that the
556 * proxy class will be defined in the same package. Verify that
557 * all non-public proxy interfaces are in the same package.
558 */
559 for (int i = 0; i < interfaces.length; i++) {
560 int flags = interfaces[i].getModifiers();
561 if (!Modifier.isPublic(flags)) {
562 accessFlags = Modifier.FINAL;
563 String name = interfaces[i].getName();
564 int n = name.lastIndexOf('.');
565 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
566 if (proxyPkg == null) {
567 proxyPkg = pkg;
568 } else if (!pkg.equals(proxyPkg)) {
569 throw new IllegalArgumentException(
570 "non-public interfaces from different packages");
571 }
572 }
573 }
574
575 if (proxyPkg == null) {
576 // if no non-public proxy interfaces, use com.sun.proxy package
577 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
578 }
579
580 {
581 /*
582 * Choose a name for the proxy class to generate.
583 */
584 long num;
585 synchronized (nextUniqueNumberLock) {
586 num = nextUniqueNumber++;
587 }
588 String proxyName = proxyPkg + proxyClassNamePrefix + num;
589 /*
590 * Verify that the class loader hasn't already
591 * defined a class with the chosen name.
592 */
593
594 /*
595 * Generate the specified proxy class.
596 */
597 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
598 proxyName, interfaces, accessFlags);
599 try {
600 proxyClass = defineClass0(loader, proxyName,
601 proxyClassFile, 0, proxyClassFile.length);
602 } catch (ClassFormatError e) {
603 /*
604 * A ClassFormatError here means that (barring bugs in the
605 * proxy class generation code) there was some other
606 * invalid aspect of the arguments supplied to the proxy
607 * class creation (such as virtual machine limitations
608 * exceeded).
609 */
610 throw new IllegalArgumentException(e.toString());
611 }
612 }
613 // add to set of all generated proxy classes, for isProxyClass
614 proxyClasses.put(proxyClass, null);
615
616 } finally {
617 /*
618 * We must clean up the "pending generation" state of the proxy
619 * class cache entry somehow. If a proxy class was successfully
620 * generated, store it in the cache (with a weak reference);
621 * otherwise, remove the reserved entry. In all cases, notify
622 * all waiters on reserved entries in this cache.
623 */
624 synchronized (cache) {
625 if (proxyClass != null) {
626 cache.put(key, new WeakReference<Class<?>>(proxyClass));
627 } else {
628 cache.remove(key);
629 }
630 cache.notifyAll();
631 }
632 }
633 return proxyClass;
634 }
635
636 /**
637 * Returns an instance of a proxy class for the specified interfaces
638 * that dispatches method invocations to the specified invocation
639 * handler.
640 *
641 * <p>{@code Proxy.newProxyInstance} throws
642 * {@code IllegalArgumentException} for the same reasons that
643 * {@code Proxy.getProxyClass} does.
644 *
645 * @param loader the class loader to define the proxy class
646 * @param interfaces the list of interfaces for the proxy class
647 * to implement
648 * @param h the invocation handler to dispatch method invocations to
649 * @return a proxy instance with the specified invocation handler of a
650 * proxy class that is defined by the specified class loader
651 * and that implements the specified interfaces
652 * @throws IllegalArgumentException if any of the restrictions on the
653 * parameters that may be passed to {@code getProxyClass}
740 return;
741 }
742
743 ClassLoader ccl = caller.getClassLoader();
744 ClassLoader pcl = proxyClass.getClassLoader();
745
746 // do permission check if the caller is in a different runtime package
747 // of the proxy class
748 int n = pcn.lastIndexOf('.');
749 String pkg = (n == -1) ? "" : pcn.substring(0, n);
750
751 n = caller.getName().lastIndexOf('.');
752 String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
753
754 if (pcl != ccl || !pkg.equals(callerPkg)) {
755 sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
756 }
757 }
758 }
759
760 private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
761 try {
762 return cons.newInstance(new Object[] {h} );
763 } catch (IllegalAccessException | InstantiationException e) {
764 throw new InternalError(e.toString(), e);
765 } catch (InvocationTargetException e) {
766 Throwable t = e.getCause();
767 if (t instanceof RuntimeException) {
768 throw (RuntimeException) t;
769 } else {
770 throw new InternalError(t.toString(), t);
771 }
772 }
773 }
774
775 /**
776 * Returns true if and only if the specified class was dynamically
777 * generated to be a proxy class using the {@code getProxyClass}
778 * method or the {@code newProxyInstance} method.
779 *
780 * <p>The reliability of this method is important for the ability
781 * to use it to make security decisions, so its implementation should
782 * not just test if the class in question extends {@code Proxy}.
783 *
784 * @param cl the class to test
785 * @return {@code true} if the class is a proxy class and
786 * {@code false} otherwise
787 * @throws NullPointerException if {@code cl} is {@code null}
788 */
789 public static boolean isProxyClass(Class<?> cl) {
790 if (cl == null) {
791 throw new NullPointerException();
792 }
793
794 return proxyClasses.containsKey(cl);
795 }
796
797 /**
798 * Returns the invocation handler for the specified proxy instance.
799 *
800 * @param proxy the proxy instance to return the invocation handler for
801 * @return the invocation handler for the proxy instance
802 * @throws IllegalArgumentException if the argument is not a
803 * proxy instance
804 */
805 public static InvocationHandler getInvocationHandler(Object proxy)
806 throws IllegalArgumentException
807 {
808 /*
809 * Verify that the object is actually a proxy instance.
810 */
811 if (!isProxyClass(proxy.getClass())) {
812 throw new IllegalArgumentException("not a proxy instance");
813 }
814
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.reflect;
27
28 import java.lang.ref.WeakReference;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import java.util.Arrays;
32 import java.util.IdentityHashMap;
33 import java.util.Map;
34 import java.util.concurrent.atomic.AtomicLong;
35 import java.util.function.BiFunction;
36 import sun.misc.ProxyGenerator;
37 import sun.misc.VM;
38 import sun.reflect.CallerSensitive;
39 import sun.reflect.Reflection;
40 import sun.reflect.misc.ReflectUtil;
41 import sun.security.util.SecurityConstants;
42
43 /**
44 * {@code Proxy} provides static methods for creating dynamic proxy
45 * classes and instances, and it is also the superclass of all
46 * dynamic proxy classes created by those methods.
47 *
48 * <p>To create a proxy for some interface {@code Foo}:
49 * <pre>
50 * InvocationHandler handler = new MyInvocationHandler(...);
51 * Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
52 * Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
53 * newInstance(handler);
54 * </pre>
55 * or more simply:
211 * types in the {@code throws} clause of the method in <i>all</i> of
212 * the proxy interfaces that it can be invoked through. If the
213 * {@code invoke} method throws a checked exception that is not
214 * assignable to any of the exception types declared by the method in one
215 * of the proxy interfaces that it can be invoked through, then an
216 * unchecked {@code UndeclaredThrowableException} will be thrown by
217 * the invocation on the proxy instance. This restriction means that not
218 * all of the exception types returned by invoking
219 * {@code getExceptionTypes} on the {@code Method} object
220 * passed to the {@code invoke} method can necessarily be thrown
221 * successfully by the {@code invoke} method.
222 *
223 * @author Peter Jones
224 * @see InvocationHandler
225 * @since 1.3
226 */
227 public class Proxy implements java.io.Serializable {
228
229 private static final long serialVersionUID = -2222568056686623797L;
230
231 /** parameter types of a proxy class constructor */
232 private static final Class<?>[] constructorParams =
233 { InvocationHandler.class };
234
235 /**
236 * a cache of proxy classes
237 */
238 private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
239 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
240
241 /**
242 * the invocation handler for this proxy instance.
243 * @serial
244 */
245 protected InvocationHandler h;
246
247 /**
248 * Prohibits instantiation.
249 */
250 private Proxy() {
251 }
252
253 /**
254 * Constructs a new {@code Proxy} instance from a subclass
255 * (typically, a dynamic proxy class) with the specified value
256 * for its invocation handler.
257 *
258 * @param h the invocation handler for this proxy instance
259 */
390 SecurityManager sm = System.getSecurityManager();
391 if (sm != null) {
392 ClassLoader ccl = caller.getClassLoader();
393 if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
394 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
395 }
396 ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
397 }
398 }
399
400 /**
401 * Generate a proxy class. Must call the checkProxyAccess method
402 * to perform permission checks before calling this.
403 */
404 private static Class<?> getProxyClass0(ClassLoader loader,
405 Class<?>... interfaces) {
406 if (interfaces.length > 65535) {
407 throw new IllegalArgumentException("interface limit exceeded");
408 }
409
410 // If the proxy class defined by the given loader implementing
411 // the given interfaces exists, this will simply return the cached copy;
412 // otherwise, it will create the proxy class via the ProxyClassFactory
413 return proxyClassCache.get(loader, interfaces);
414 }
415
416 /*
417 * a key used for proxy class with 0 implemented interfaces
418 */
419 private static final Object key0 = new Object();
420
421 /*
422 * Key1 and Key2 are optimized for the common use of dynamic proxies
423 * that implement 1 or 2 interfaces.
424 */
425
426 /*
427 * a key used for proxy class with 1 implemented interface
428 */
429 private static final class Key1 extends WeakReference<Class<?>> {
430 private final int hash;
431
432 Key1(Class<?> intf) {
433 super(intf);
434 this.hash = intf.hashCode();
435 }
436
437 @Override
438 public int hashCode() {
439 return hash;
440 }
441
442 @Override
443 public boolean equals(Object obj) {
444 Class<?> intf;
445 return this == obj ||
446 obj != null &&
447 obj.getClass() == Key1.class &&
448 (intf = get()) != null &&
449 intf == ((Key1) obj).get();
450 }
451 }
452
453 /*
454 * a key used for proxy class with 2 implemented interfaces
455 */
456 private static final class Key2 extends WeakReference<Class<?>> {
457 private final int hash;
458 private final WeakReference<Class<?>> ref2;
459
460 Key2(Class<?> intf1, Class<?> intf2) {
461 super(intf1);
462 hash = 31 * intf1.hashCode() + intf2.hashCode();
463 ref2 = new WeakReference<Class<?>>(intf2);
464 }
465
466 @Override
467 public int hashCode() {
468 return hash;
469 }
470
471 @Override
472 public boolean equals(Object obj) {
473 Class<?> intf1, intf2;
474 return this == obj ||
475 obj != null &&
476 obj.getClass() == Key2.class &&
477 (intf1 = get()) != null &&
478 intf1 == ((Key2) obj).get() &&
479 (intf2 = ref2.get()) != null &&
480 intf2 == ((Key2) obj).ref2.get();
481 }
482 }
483
484 /*
485 * a key used for proxy class with any number of implemented interfaces
486 * (used here for 3 or more only)
487 */
488 private static final class KeyX {
489 private final int hash;
490 private final WeakReference<Class<?>>[] refs;
491
492 KeyX(Class<?>[] interfaces) {
493 hash = Arrays.hashCode(interfaces);
494 refs = new WeakReference[interfaces.length];
495 for (int i = 0; i < interfaces.length; i++) {
496 refs[i] = new WeakReference<>(interfaces[i]);
497 }
498 }
499
500 @Override
501 public int hashCode() {
502 return hash;
503 }
504
505 @Override
506 public boolean equals(Object obj) {
507 return this == obj ||
508 obj != null &&
509 obj.getClass() == KeyX.class &&
510 equals(refs, ((KeyX) obj).refs);
511 }
512
513 private static boolean equals(WeakReference<Class<?>>[] refs1,
514 WeakReference<Class<?>>[] refs2) {
515 if (refs1.length != refs2.length) {
516 return false;
517 }
518 for (int i = 0; i < refs1.length; i++) {
519 Class<?> intf = refs1[i].get();
520 if (intf == null || intf != refs2[i].get()) {
521 return false;
522 }
523 }
524 return true;
525 }
526 }
527
528 /**
529 * A function that maps an array of interfaces to an optimal key where
530 * Class objects representing interfaces are weakly referenced.
531 */
532 private static final class KeyFactory
533 implements BiFunction<ClassLoader, Class<?>[], Object>
534 {
535 @Override
536 public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
537 switch (interfaces.length) {
538 case 1: return new Key1(interfaces[0]); // the most frequent
539 case 2: return new Key2(interfaces[0], interfaces[1]);
540 case 0: return key0;
541 default: return new KeyX(interfaces);
542 }
543 }
544 }
545
546 /**
547 * A factory function that generates, defines and returns the proxy class given
548 * the ClassLoader and array of interfaces.
549 */
550 private static final class ProxyClassFactory
551 implements BiFunction<ClassLoader, Class<?>[], Class<?>>
552 {
553 // prefix for all proxy class names
554 private static final String proxyClassNamePrefix = "$Proxy";
555
556 // next number to use for generation of unique proxy class names
557 private static final AtomicLong nextUniqueNumber = new AtomicLong();
558
559 @Override
560 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
561
562 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
563 for (Class<?> intf : interfaces) {
564 /*
565 * Verify that the class loader resolves the name of this
566 * interface to the same Class object.
567 */
568 Class<?> interfaceClass = null;
569 try {
570 interfaceClass = Class.forName(intf.getName(), false, loader);
571 } catch (ClassNotFoundException e) {
572 }
573 if (interfaceClass != intf) {
574 throw new IllegalArgumentException(
575 intf + " is not visible from class loader");
576 }
577 /*
578 * Verify that the Class object actually represents an
579 * interface.
580 */
581 if (!interfaceClass.isInterface()) {
582 throw new IllegalArgumentException(
583 interfaceClass.getName() + " is not an interface");
584 }
585 /*
586 * Verify that this interface is not a duplicate.
587 */
588 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
589 throw new IllegalArgumentException(
590 "repeated interface: " + interfaceClass.getName());
591 }
592 }
593
594 String proxyPkg = null; // package to define proxy class in
595 int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
596
597 /*
598 * Record the package of a non-public proxy interface so that the
599 * proxy class will be defined in the same package. Verify that
600 * all non-public proxy interfaces are in the same package.
601 */
602 for (Class<?> intf : interfaces) {
603 int flags = intf.getModifiers();
604 if (!Modifier.isPublic(flags)) {
605 accessFlags = Modifier.FINAL;
606 String name = intf.getName();
607 int n = name.lastIndexOf('.');
608 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
609 if (proxyPkg == null) {
610 proxyPkg = pkg;
611 } else if (!pkg.equals(proxyPkg)) {
612 throw new IllegalArgumentException(
613 "non-public interfaces from different packages");
614 }
615 }
616 }
617
618 if (proxyPkg == null) {
619 // if no non-public proxy interfaces, use com.sun.proxy package
620 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
621 }
622
623 /*
624 * Choose a name for the proxy class to generate.
625 */
626 long num = nextUniqueNumber.getAndIncrement();
627 String proxyName = proxyPkg + proxyClassNamePrefix + num;
628
629 /*
630 * Generate the specified proxy class.
631 */
632 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
633 proxyName, interfaces, accessFlags);
634 try {
635 return defineClass0(loader, proxyName,
636 proxyClassFile, 0, proxyClassFile.length);
637 } catch (ClassFormatError e) {
638 /*
639 * A ClassFormatError here means that (barring bugs in the
640 * proxy class generation code) there was some other
641 * invalid aspect of the arguments supplied to the proxy
642 * class creation (such as virtual machine limitations
643 * exceeded).
644 */
645 throw new IllegalArgumentException(e.toString());
646 }
647 }
648 }
649
650 /**
651 * Returns an instance of a proxy class for the specified interfaces
652 * that dispatches method invocations to the specified invocation
653 * handler.
654 *
655 * <p>{@code Proxy.newProxyInstance} throws
656 * {@code IllegalArgumentException} for the same reasons that
657 * {@code Proxy.getProxyClass} does.
658 *
659 * @param loader the class loader to define the proxy class
660 * @param interfaces the list of interfaces for the proxy class
661 * to implement
662 * @param h the invocation handler to dispatch method invocations to
663 * @return a proxy instance with the specified invocation handler of a
664 * proxy class that is defined by the specified class loader
665 * and that implements the specified interfaces
666 * @throws IllegalArgumentException if any of the restrictions on the
667 * parameters that may be passed to {@code getProxyClass}
754 return;
755 }
756
757 ClassLoader ccl = caller.getClassLoader();
758 ClassLoader pcl = proxyClass.getClassLoader();
759
760 // do permission check if the caller is in a different runtime package
761 // of the proxy class
762 int n = pcn.lastIndexOf('.');
763 String pkg = (n == -1) ? "" : pcn.substring(0, n);
764
765 n = caller.getName().lastIndexOf('.');
766 String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
767
768 if (pcl != ccl || !pkg.equals(callerPkg)) {
769 sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
770 }
771 }
772 }
773
774 /**
775 * Returns true if and only if the specified class was dynamically
776 * generated to be a proxy class using the {@code getProxyClass}
777 * method or the {@code newProxyInstance} method.
778 *
779 * <p>The reliability of this method is important for the ability
780 * to use it to make security decisions, so its implementation should
781 * not just test if the class in question extends {@code Proxy}.
782 *
783 * @param cl the class to test
784 * @return {@code true} if the class is a proxy class and
785 * {@code false} otherwise
786 * @throws NullPointerException if {@code cl} is {@code null}
787 */
788 public static boolean isProxyClass(Class<?> cl) {
789 return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
790 }
791
792 /**
793 * Returns the invocation handler for the specified proxy instance.
794 *
795 * @param proxy the proxy instance to return the invocation handler for
796 * @return the invocation handler for the proxy instance
797 * @throws IllegalArgumentException if the argument is not a
798 * proxy instance
799 */
800 public static InvocationHandler getInvocationHandler(Object proxy)
801 throws IllegalArgumentException
802 {
803 /*
804 * Verify that the object is actually a proxy instance.
805 */
806 if (!isProxyClass(proxy.getClass())) {
807 throw new IllegalArgumentException("not a proxy instance");
808 }
809
|