421 Class<?>... interfaces) { |
405 Class<?>... interfaces) { |
422 if (interfaces.length > 65535) { |
406 if (interfaces.length > 65535) { |
423 throw new IllegalArgumentException("interface limit exceeded"); |
407 throw new IllegalArgumentException("interface limit exceeded"); |
424 } |
408 } |
425 |
409 |
426 Class<?> proxyClass = null; |
410 // If the proxy class defined by the given loader implementing |
427 |
411 // the given interfaces exists, this will simply return the cached copy; |
428 /* collect interface names to use as key for proxy class cache */ |
412 // otherwise, it will create the proxy class via the ProxyClassFactory |
429 String[] interfaceNames = new String[interfaces.length]; |
413 return proxyClassCache.get(loader, interfaces); |
430 |
414 } |
431 // for detecting duplicates |
415 |
432 Set<Class<?>> interfaceSet = new HashSet<>(); |
416 /* |
433 |
417 * a key used for proxy class with 0 implemented interfaces |
434 for (int i = 0; i < interfaces.length; i++) { |
418 */ |
435 /* |
419 private static final Object key0 = new Object(); |
436 * Verify that the class loader resolves the name of this |
420 |
437 * interface to the same Class object. |
421 /* |
438 */ |
422 * Key1 and Key2 are optimized for the common use of dynamic proxies |
439 String interfaceName = interfaces[i].getName(); |
423 * that implement 1 or 2 interfaces. |
440 Class<?> interfaceClass = null; |
424 */ |
441 try { |
425 |
442 interfaceClass = Class.forName(interfaceName, false, loader); |
426 /* |
443 } catch (ClassNotFoundException e) { |
427 * a key used for proxy class with 1 implemented interface |
444 } |
428 */ |
445 if (interfaceClass != interfaces[i]) { |
429 private static final class Key1 extends WeakReference<Class<?>> { |
446 throw new IllegalArgumentException( |
430 private final int hash; |
447 interfaces[i] + " is not visible from class loader"); |
431 |
448 } |
432 Key1(Class<?> intf) { |
449 |
433 super(intf); |
450 /* |
434 this.hash = intf.hashCode(); |
451 * Verify that the Class object actually represents an |
435 } |
452 * interface. |
436 |
453 */ |
437 @Override |
454 if (!interfaceClass.isInterface()) { |
438 public int hashCode() { |
455 throw new IllegalArgumentException( |
439 return hash; |
456 interfaceClass.getName() + " is not an interface"); |
440 } |
457 } |
441 |
458 |
442 @Override |
459 /* |
443 public boolean equals(Object obj) { |
460 * Verify that this interface is not a duplicate. |
444 Class<?> intf; |
461 */ |
445 return this == obj || |
462 if (interfaceSet.contains(interfaceClass)) { |
446 obj != null && |
463 throw new IllegalArgumentException( |
447 obj.getClass() == Key1.class && |
464 "repeated interface: " + interfaceClass.getName()); |
448 (intf = get()) != null && |
465 } |
449 intf == ((Key1) obj).get(); |
466 interfaceSet.add(interfaceClass); |
450 } |
467 |
451 } |
468 interfaceNames[i] = interfaceName; |
452 |
469 } |
453 /* |
470 |
454 * a key used for proxy class with 2 implemented interfaces |
471 /* |
455 */ |
472 * Using string representations of the proxy interfaces as |
456 private static final class Key2 extends WeakReference<Class<?>> { |
473 * keys in the proxy class cache (instead of their Class |
457 private final int hash; |
474 * objects) is sufficient because we require the proxy |
458 private final WeakReference<Class<?>> ref2; |
475 * interfaces to be resolvable by name through the supplied |
459 |
476 * class loader, and it has the advantage that using a string |
460 Key2(Class<?> intf1, Class<?> intf2) { |
477 * representation of a class makes for an implicit weak |
461 super(intf1); |
478 * reference to the class. |
462 hash = 31 * intf1.hashCode() + intf2.hashCode(); |
479 */ |
463 ref2 = new WeakReference<Class<?>>(intf2); |
480 List<String> key = Arrays.asList(interfaceNames); |
464 } |
481 |
465 |
482 /* |
466 @Override |
483 * Find or create the proxy class cache for the class loader. |
467 public int hashCode() { |
484 */ |
468 return hash; |
485 Map<List<String>, Object> cache; |
469 } |
486 synchronized (loaderToCache) { |
470 |
487 cache = loaderToCache.get(loader); |
471 @Override |
488 if (cache == null) { |
472 public boolean equals(Object obj) { |
489 cache = new HashMap<>(); |
473 Class<?> intf1, intf2; |
490 loaderToCache.put(loader, cache); |
474 return this == obj || |
491 } |
475 obj != null && |
492 /* |
476 obj.getClass() == Key2.class && |
493 * This mapping will remain valid for the duration of this |
477 (intf1 = get()) != null && |
494 * method, without further synchronization, because the mapping |
478 intf1 == ((Key2) obj).get() && |
495 * will only be removed if the class loader becomes unreachable. |
479 (intf2 = ref2.get()) != null && |
496 */ |
480 intf2 == ((Key2) obj).ref2.get(); |
497 } |
481 } |
498 |
482 } |
499 /* |
483 |
500 * Look up the list of interfaces in the proxy class cache using |
484 /* |
501 * the key. This lookup will result in one of three possible |
485 * a key used for proxy class with any number of implemented interfaces |
502 * kinds of values: |
486 * (used here for 3 or more only) |
503 * null, if there is currently no proxy class for the list of |
487 */ |
504 * interfaces in the class loader, |
488 private static final class KeyX { |
505 * the pendingGenerationMarker object, if a proxy class for the |
489 private final int hash; |
506 * list of interfaces is currently being generated, |
490 private final WeakReference<Class<?>>[] refs; |
507 * or a weak reference to a Class object, if a proxy class for |
491 |
508 * the list of interfaces has already been generated. |
492 KeyX(Class<?>[] interfaces) { |
509 */ |
493 hash = Arrays.hashCode(interfaces); |
510 synchronized (cache) { |
494 refs = new WeakReference[interfaces.length]; |
511 /* |
495 for (int i = 0; i < interfaces.length; i++) { |
512 * Note that we need not worry about reaping the cache for |
496 refs[i] = new WeakReference<>(interfaces[i]); |
513 * entries with cleared weak references because if a proxy class |
497 } |
514 * has been garbage collected, its class loader will have been |
498 } |
515 * garbage collected as well, so the entire cache will be reaped |
499 |
516 * from the loaderToCache map. |
500 @Override |
517 */ |
501 public int hashCode() { |
518 do { |
502 return hash; |
519 Object value = cache.get(key); |
503 } |
520 if (value instanceof Reference) { |
504 |
521 proxyClass = (Class<?>) ((Reference) value).get(); |
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 } |
522 } |
523 if (proxyClass != null) { |
523 } |
524 // proxy class already generated: return it |
524 return true; |
525 return proxyClass; |
525 } |
526 } else if (value == pendingGenerationMarker) { |
526 } |
527 // proxy class being generated: wait for it |
527 |
528 try { |
528 /** |
529 cache.wait(); |
529 * A function that maps an array of interfaces to an optimal key where |
530 } catch (InterruptedException e) { |
530 * Class objects representing interfaces are weakly referenced. |
531 /* |
531 */ |
532 * The class generation that we are waiting for should |
532 private static final class KeyFactory |
533 * take a small, bounded time, so we can safely ignore |
533 implements BiFunction<ClassLoader, Class<?>[], Object> |
534 * thread interrupts here. |
534 { |
535 */ |
535 @Override |
536 } |
536 public Object apply(ClassLoader classLoader, Class<?>[] interfaces) { |
537 continue; |
537 switch (interfaces.length) { |
538 } else { |
538 case 1: return new Key1(interfaces[0]); // the most frequent |
539 /* |
539 case 2: return new Key2(interfaces[0], interfaces[1]); |
540 * No proxy class for this list of interfaces has been |
540 case 0: return key0; |
541 * generated or is being generated, so we will go and |
541 default: return new KeyX(interfaces); |
542 * generate it now. Mark it as pending generation. |
542 } |
543 */ |
543 } |
544 cache.put(key, pendingGenerationMarker); |
544 } |
545 break; |
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) { |
546 } |
572 } |
547 } while (true); |
573 if (interfaceClass != intf) { |
548 } |
574 throw new IllegalArgumentException( |
549 |
575 intf + " is not visible from class loader"); |
550 try { |
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 |
551 String proxyPkg = null; // package to define proxy class in |
594 String proxyPkg = null; // package to define proxy class in |
552 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; |
595 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; |
553 |
596 |
554 /* |
597 /* |
555 * Record the package of a non-public proxy interface so that the |
598 * Record the package of a non-public proxy interface so that the |
556 * proxy class will be defined in the same package. Verify that |
599 * proxy class will be defined in the same package. Verify that |
557 * all non-public proxy interfaces are in the same package. |
600 * all non-public proxy interfaces are in the same package. |
558 */ |
601 */ |
559 for (int i = 0; i < interfaces.length; i++) { |
602 for (Class<?> intf : interfaces) { |
560 int flags = interfaces[i].getModifiers(); |
603 int flags = intf.getModifiers(); |
561 if (!Modifier.isPublic(flags)) { |
604 if (!Modifier.isPublic(flags)) { |
562 accessFlags = Modifier.FINAL; |
605 accessFlags = Modifier.FINAL; |
563 String name = interfaces[i].getName(); |
606 String name = intf.getName(); |
564 int n = name.lastIndexOf('.'); |
607 int n = name.lastIndexOf('.'); |
565 String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); |
608 String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); |
566 if (proxyPkg == null) { |
609 if (proxyPkg == null) { |
567 proxyPkg = pkg; |
610 proxyPkg = pkg; |
568 } else if (!pkg.equals(proxyPkg)) { |
611 } else if (!pkg.equals(proxyPkg)) { |
575 if (proxyPkg == null) { |
618 if (proxyPkg == null) { |
576 // if no non-public proxy interfaces, use com.sun.proxy package |
619 // if no non-public proxy interfaces, use com.sun.proxy package |
577 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; |
620 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; |
578 } |
621 } |
579 |
622 |
580 { |
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) { |
581 /* |
638 /* |
582 * Choose a name for the proxy class to generate. |
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). |
583 */ |
644 */ |
584 long num; |
645 throw new IllegalArgumentException(e.toString()); |
585 synchronized (nextUniqueNumberLock) { |
646 } |
586 num = nextUniqueNumber++; |
647 } |
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 } |
648 } |
635 |
649 |
636 /** |
650 /** |
637 * Returns an instance of a proxy class for the specified interfaces |
651 * Returns an instance of a proxy class for the specified interfaces |
638 * that dispatches method invocations to the specified invocation |
652 * that dispatches method invocations to the specified invocation |