224 * <p> |
224 * <p> |
225 * A lookup can fail, because |
225 * A lookup can fail, because |
226 * the containing class is not accessible to the lookup class, or |
226 * the containing class is not accessible to the lookup class, or |
227 * because the desired class member is missing, or because the |
227 * because the desired class member is missing, or because the |
228 * desired class member is not accessible to the lookup class. |
228 * desired class member is not accessible to the lookup class. |
229 * It can also fail if a security manager is installed and refuses |
229 * In any of these cases, a {@code ReflectiveOperationException} will be |
230 * access. In any of these cases, an exception will be |
230 * thrown from the attempted lookup. The exact class will be one of |
231 * thrown from the attempted lookup. |
231 * the following: |
|
232 * <ul> |
|
233 * <li>NoSuchMethodException — if a method is requested but does not exist |
|
234 * <li>NoSuchFieldException — if a field is requested but does not exist |
|
235 * <li>IllegalAccessException — if the member exists but an access check fails |
|
236 * </ul> |
232 * <p> |
237 * <p> |
233 * In general, the conditions under which a method handle may be |
238 * In general, the conditions under which a method handle may be |
234 * looked up for a method {@code M} are exactly equivalent to the conditions |
239 * looked up for a method {@code M} are exactly equivalent to the conditions |
235 * under which the lookup class could have compiled and resolved a call to {@code M}. |
240 * under which the lookup class could have compiled and resolved a call to {@code M}. |
236 * And the effect of invoking the method handle resulting from the lookup |
241 * And the effect of invoking the method handle resulting from the lookup |
509 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
514 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
510 * @param refc the class from which the method is accessed |
515 * @param refc the class from which the method is accessed |
511 * @param name the name of the method |
516 * @param name the name of the method |
512 * @param type the type of the method |
517 * @param type the type of the method |
513 * @return the desired method handle |
518 * @return the desired method handle |
514 * @exception NoAccessException if the method does not exist or access checking fails |
519 * @throws NoSuchMethodException if the method does not exist |
|
520 * @throws IllegalAccessException if access checking fails, or if the method is not {@code static} |
|
521 * @throws NullPointerException if any argument is null |
515 */ |
522 */ |
516 public |
523 public |
517 MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoAccessException { |
524 MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { |
518 MemberName method = resolveOrFail(refc, name, type, true); |
525 MemberName method = resolveOrFail(refc, name, type, true); |
519 checkMethod(refc, method, true); |
526 checkMethod(refc, method, true); |
520 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); |
527 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); |
521 } |
528 } |
522 |
529 |
547 * |
554 * |
548 * @param refc the class or interface from which the method is accessed |
555 * @param refc the class or interface from which the method is accessed |
549 * @param name the name of the method |
556 * @param name the name of the method |
550 * @param type the type of the method, with the receiver argument omitted |
557 * @param type the type of the method, with the receiver argument omitted |
551 * @return the desired method handle |
558 * @return the desired method handle |
552 * @exception NoAccessException if the method does not exist or access checking fails |
559 * @throws NoSuchMethodException if the method does not exist |
553 */ |
560 * @throws IllegalAccessException if access checking fails, or if the method is {@code static} |
554 public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoAccessException { |
561 * @throws NullPointerException if any argument is null |
|
562 */ |
|
563 public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { |
555 MemberName method = resolveOrFail(refc, name, type, false); |
564 MemberName method = resolveOrFail(refc, name, type, false); |
556 checkMethod(refc, method, false); |
565 checkMethod(refc, method, false); |
557 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
566 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
558 return restrictProtectedReceiver(method, mh); |
567 return restrictProtectedReceiver(method, mh); |
559 } |
568 } |
574 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
583 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
575 * the constructor's variable arity modifier bit ({@code 0x0080}) is set. |
584 * the constructor's variable arity modifier bit ({@code 0x0080}) is set. |
576 * @param refc the class or interface from which the method is accessed |
585 * @param refc the class or interface from which the method is accessed |
577 * @param type the type of the method, with the receiver argument omitted, and a void return type |
586 * @param type the type of the method, with the receiver argument omitted, and a void return type |
578 * @return the desired method handle |
587 * @return the desired method handle |
579 * @exception NoAccessException if the method does not exist or access checking fails |
588 * @throws NoSuchMethodException if the constructor does not exist |
580 */ |
589 * @throws IllegalAccessException if access checking fails |
581 public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoAccessException { |
590 * @throws NullPointerException if any argument is null |
|
591 */ |
|
592 public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { |
582 String name = "<init>"; |
593 String name = "<init>"; |
583 MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); |
594 MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); |
584 assert(ctor.isConstructor()); |
595 assert(ctor.isConstructor()); |
585 checkAccess(refc, ctor); |
596 checkAccess(refc, ctor); |
586 MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); |
597 MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); |
627 * @param refc the class or interface from which the method is accessed |
638 * @param refc the class or interface from which the method is accessed |
628 * @param name the name of the method (which must not be "<init>") |
639 * @param name the name of the method (which must not be "<init>") |
629 * @param type the type of the method, with the receiver argument omitted |
640 * @param type the type of the method, with the receiver argument omitted |
630 * @param specialCaller the proposed calling class to perform the {@code invokespecial} |
641 * @param specialCaller the proposed calling class to perform the {@code invokespecial} |
631 * @return the desired method handle |
642 * @return the desired method handle |
632 * @exception NoAccessException if the method does not exist or access checking fails |
643 * @throws NoSuchMethodException if the method does not exist |
|
644 * @throws IllegalAccessException if access checking fails |
|
645 * @throws NullPointerException if any argument is null |
633 */ |
646 */ |
634 public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, |
647 public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, |
635 Class<?> specialCaller) throws NoAccessException { |
648 Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { |
636 checkSpecialCaller(specialCaller); |
649 checkSpecialCaller(specialCaller); |
637 MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); |
650 MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); |
638 checkMethod(refc, method, false); |
651 checkMethod(refc, method, false); |
639 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); |
652 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); |
640 return restrictReceiver(method, mh, specialCaller); |
653 return restrictReceiver(method, mh, specialCaller); |
649 * Access checking is performed immediately on behalf of the lookup class. |
662 * Access checking is performed immediately on behalf of the lookup class. |
650 * @param refc the class or interface from which the method is accessed |
663 * @param refc the class or interface from which the method is accessed |
651 * @param name the field's name |
664 * @param name the field's name |
652 * @param type the field's type |
665 * @param type the field's type |
653 * @return a method handle which can load values from the field |
666 * @return a method handle which can load values from the field |
654 * @exception NoAccessException if access checking fails |
667 * @throws NoSuchFieldException if the field does not exist |
655 */ |
668 * @throws IllegalAccessException if access checking fails, or if the field is {@code static} |
656 public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoAccessException { |
669 * @throws NullPointerException if any argument is null |
|
670 */ |
|
671 public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
657 return makeAccessor(refc, name, type, false, false); |
672 return makeAccessor(refc, name, type, false, false); |
658 } |
673 } |
659 |
674 |
660 /** |
675 /** |
661 * Produces a method handle giving write access to a non-static field. |
676 * Produces a method handle giving write access to a non-static field. |
666 * Access checking is performed immediately on behalf of the lookup class. |
681 * Access checking is performed immediately on behalf of the lookup class. |
667 * @param refc the class or interface from which the method is accessed |
682 * @param refc the class or interface from which the method is accessed |
668 * @param name the field's name |
683 * @param name the field's name |
669 * @param type the field's type |
684 * @param type the field's type |
670 * @return a method handle which can store values into the field |
685 * @return a method handle which can store values into the field |
671 * @exception NoAccessException if access checking fails |
686 * @throws NoSuchFieldException if the field does not exist |
672 */ |
687 * @throws IllegalAccessException if access checking fails, or if the field is {@code static} |
673 public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoAccessException { |
688 * @throws NullPointerException if any argument is null |
|
689 */ |
|
690 public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
674 return makeAccessor(refc, name, type, false, true); |
691 return makeAccessor(refc, name, type, false, true); |
675 } |
692 } |
676 |
693 |
677 /** |
694 /** |
678 * Produces a method handle giving read access to a static field. |
695 * Produces a method handle giving read access to a static field. |
682 * Access checking is performed immediately on behalf of the lookup class. |
699 * Access checking is performed immediately on behalf of the lookup class. |
683 * @param refc the class or interface from which the method is accessed |
700 * @param refc the class or interface from which the method is accessed |
684 * @param name the field's name |
701 * @param name the field's name |
685 * @param type the field's type |
702 * @param type the field's type |
686 * @return a method handle which can load values from the field |
703 * @return a method handle which can load values from the field |
687 * @exception NoAccessException if access checking fails |
704 * @throws NoSuchFieldException if the field does not exist |
688 */ |
705 * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} |
689 public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoAccessException { |
706 * @throws NullPointerException if any argument is null |
|
707 */ |
|
708 public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
690 return makeAccessor(refc, name, type, true, false); |
709 return makeAccessor(refc, name, type, true, false); |
691 } |
710 } |
692 |
711 |
693 /** |
712 /** |
694 * Produces a method handle giving write access to a static field. |
713 * Produces a method handle giving write access to a static field. |
698 * Access checking is performed immediately on behalf of the lookup class. |
717 * Access checking is performed immediately on behalf of the lookup class. |
699 * @param refc the class or interface from which the method is accessed |
718 * @param refc the class or interface from which the method is accessed |
700 * @param name the field's name |
719 * @param name the field's name |
701 * @param type the field's type |
720 * @param type the field's type |
702 * @return a method handle which can store values into the field |
721 * @return a method handle which can store values into the field |
703 * @exception NoAccessException if access checking fails |
722 * @throws NoSuchFieldException if the field does not exist |
704 */ |
723 * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} |
705 public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoAccessException { |
724 * @throws NullPointerException if any argument is null |
|
725 */ |
|
726 public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { |
706 return makeAccessor(refc, name, type, true, true); |
727 return makeAccessor(refc, name, type, true, true); |
707 } |
728 } |
708 |
729 |
709 /** |
730 /** |
710 * Produces an early-bound method handle for a non-static method. |
731 * Produces an early-bound method handle for a non-static method. |
739 * (Note that {@code bindTo} does not preserve variable arity.) |
760 * (Note that {@code bindTo} does not preserve variable arity.) |
740 * @param receiver the object from which the method is accessed |
761 * @param receiver the object from which the method is accessed |
741 * @param name the name of the method |
762 * @param name the name of the method |
742 * @param type the type of the method, with the receiver argument omitted |
763 * @param type the type of the method, with the receiver argument omitted |
743 * @return the desired method handle |
764 * @return the desired method handle |
744 * @exception NoAccessException if the method does not exist or access checking fails |
765 * @throws NoSuchMethodException if the method does not exist |
745 */ |
766 * @throws IllegalAccessException if access checking fails |
746 public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { |
767 * @throws NullPointerException if any argument is null |
|
768 */ |
|
769 public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { |
747 Class<? extends Object> refc = receiver.getClass(); // may get NPE |
770 Class<? extends Object> refc = receiver.getClass(); // may get NPE |
748 MemberName method = resolveOrFail(refc, name, type, false); |
771 MemberName method = resolveOrFail(refc, name, type, false); |
749 checkMethod(refc, method, false); |
772 checkMethod(refc, method, false); |
750 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
773 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
751 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); |
774 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); |
752 if (bmh == null) |
775 if (bmh == null) |
753 throw newNoAccessException(method, lookupClass()); |
776 throw newNoAccessException(method, this); |
754 if (dmh.type().parameterCount() == 0) |
777 if (dmh.type().parameterCount() == 0) |
755 return dmh; // bound the trailing parameter; no varargs possible |
778 return dmh; // bound the trailing parameter; no varargs possible |
756 return fixVarargs(bmh, dmh); |
779 return fixVarargs(bmh, dmh); |
757 } |
780 } |
758 |
781 |
770 * The returned method handle will have |
793 * The returned method handle will have |
771 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
794 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
772 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
795 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
773 * @param m the reflected method |
796 * @param m the reflected method |
774 * @return a method handle which can invoke the reflected method |
797 * @return a method handle which can invoke the reflected method |
775 * @exception NoAccessException if access checking fails |
798 * @throws IllegalAccessException if access checking fails |
776 */ |
799 * @throws NullPointerException if the argument is null |
777 public MethodHandle unreflect(Method m) throws NoAccessException { |
800 */ |
|
801 public MethodHandle unreflect(Method m) throws IllegalAccessException { |
778 MemberName method = new MemberName(m); |
802 MemberName method = new MemberName(m); |
779 assert(method.isMethod()); |
803 assert(method.isMethod()); |
780 if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); |
804 if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); |
781 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
805 MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); |
782 if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); |
806 if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); |
797 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
821 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
798 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
822 * the method's variable arity modifier bit ({@code 0x0080}) is set. |
799 * @param m the reflected method |
823 * @param m the reflected method |
800 * @param specialCaller the class nominally calling the method |
824 * @param specialCaller the class nominally calling the method |
801 * @return a method handle which can invoke the reflected method |
825 * @return a method handle which can invoke the reflected method |
802 * @exception NoAccessException if access checking fails |
826 * @throws IllegalAccessException if access checking fails |
803 */ |
827 * @throws NullPointerException if any argument is null |
804 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException { |
828 */ |
|
829 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException { |
805 checkSpecialCaller(specialCaller); |
830 checkSpecialCaller(specialCaller); |
806 MemberName method = new MemberName(m); |
831 MemberName method = new MemberName(m); |
807 assert(method.isMethod()); |
832 assert(method.isMethod()); |
808 // ignore m.isAccessible: this is a new kind of access |
833 // ignore m.isAccessible: this is a new kind of access |
809 checkMethod(m.getDeclaringClass(), method, false); |
834 checkMethod(m.getDeclaringClass(), method, false); |
825 * The returned method handle will have |
850 * The returned method handle will have |
826 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
851 * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if |
827 * the constructor's variable arity modifier bit ({@code 0x0080}) is set. |
852 * the constructor's variable arity modifier bit ({@code 0x0080}) is set. |
828 * @param c the reflected constructor |
853 * @param c the reflected constructor |
829 * @return a method handle which can invoke the reflected constructor |
854 * @return a method handle which can invoke the reflected constructor |
830 * @exception NoAccessException if access checking fails |
855 * @throws IllegalAccessException if access checking fails |
831 */ |
856 * @throws NullPointerException if the argument is null |
832 public MethodHandle unreflectConstructor(Constructor c) throws NoAccessException { |
857 */ |
|
858 public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { |
833 MemberName ctor = new MemberName(c); |
859 MemberName ctor = new MemberName(c); |
834 assert(ctor.isConstructor()); |
860 assert(ctor.isConstructor()); |
835 if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor); |
861 if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor); |
836 MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); |
862 MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); |
837 MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor); |
863 MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor); |
864 * the field, and the value to be stored. |
891 * the field, and the value to be stored. |
865 * If the method's {@code accessible} flag is not set, |
892 * If the method's {@code accessible} flag is not set, |
866 * access checking is performed immediately on behalf of the lookup class. |
893 * access checking is performed immediately on behalf of the lookup class. |
867 * @param f the reflected field |
894 * @param f the reflected field |
868 * @return a method handle which can store values into the reflected field |
895 * @return a method handle which can store values into the reflected field |
869 * @exception NoAccessException if access checking fails |
896 * @throws IllegalAccessException if access checking fails |
870 */ |
897 * @throws NullPointerException if the argument is null |
871 public MethodHandle unreflectSetter(Field f) throws NoAccessException { |
898 */ |
|
899 public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { |
872 return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true); |
900 return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true); |
873 } |
901 } |
874 |
902 |
875 /// Helper methods, all package-private. |
903 /// Helper methods, all package-private. |
876 |
904 |
877 MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoAccessException { |
905 MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoSuchFieldException, IllegalAccessException { |
878 checkSymbolicClass(refc); // do this before attempting to resolve |
906 checkSymbolicClass(refc); // do this before attempting to resolve |
|
907 name.getClass(); type.getClass(); // NPE |
879 int mods = (isStatic ? Modifier.STATIC : 0); |
908 int mods = (isStatic ? Modifier.STATIC : 0); |
880 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); |
909 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), |
881 } |
910 NoSuchFieldException.class); |
882 |
911 } |
883 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) throws NoAccessException { |
912 |
|
913 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) throws NoSuchMethodException, IllegalAccessException { |
884 checkSymbolicClass(refc); // do this before attempting to resolve |
914 checkSymbolicClass(refc); // do this before attempting to resolve |
|
915 name.getClass(); type.getClass(); // NPE |
885 int mods = (isStatic ? Modifier.STATIC : 0); |
916 int mods = (isStatic ? Modifier.STATIC : 0); |
886 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); |
917 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), |
|
918 NoSuchMethodException.class); |
887 } |
919 } |
888 |
920 |
889 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic, |
921 MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic, |
890 boolean searchSupers, Class<?> specialCaller) throws NoAccessException { |
922 boolean searchSupers, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { |
891 checkSymbolicClass(refc); // do this before attempting to resolve |
923 checkSymbolicClass(refc); // do this before attempting to resolve |
|
924 name.getClass(); type.getClass(); // NPE |
892 int mods = (isStatic ? Modifier.STATIC : 0); |
925 int mods = (isStatic ? Modifier.STATIC : 0); |
893 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller); |
926 return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller, |
894 } |
927 NoSuchMethodException.class); |
895 |
928 } |
896 void checkSymbolicClass(Class<?> refc) throws NoAccessException { |
929 |
|
930 void checkSymbolicClass(Class<?> refc) throws IllegalAccessException { |
897 Class<?> caller = lookupClassOrNull(); |
931 Class<?> caller = lookupClassOrNull(); |
898 if (caller != null && !VerifyAccess.isClassAccessible(refc, caller)) |
932 if (caller != null && !VerifyAccess.isClassAccessible(refc, caller)) |
899 throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller); |
933 throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), this); |
900 } |
934 } |
901 |
935 |
902 void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws NoAccessException { |
936 void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws IllegalAccessException { |
903 String message; |
937 String message; |
904 if (m.isConstructor()) |
938 if (m.isConstructor()) |
905 message = "expected a method, not a constructor"; |
939 message = "expected a method, not a constructor"; |
906 else if (!m.isMethod()) |
940 else if (!m.isMethod()) |
907 message = "expected a method"; |
941 message = "expected a method"; |
908 else if (wantStatic != m.isStatic()) |
942 else if (wantStatic != m.isStatic()) |
909 message = wantStatic ? "expected a static method" : "expected a non-static method"; |
943 message = wantStatic ? "expected a static method" : "expected a non-static method"; |
910 else |
944 else |
911 { checkAccess(refc, m); return; } |
945 { checkAccess(refc, m); return; } |
912 throw newNoAccessException(message, m, lookupClass()); |
946 throw newNoAccessException(message, m, this); |
913 } |
947 } |
914 |
948 |
915 void checkAccess(Class<?> refc, MemberName m) throws NoAccessException { |
949 void checkAccess(Class<?> refc, MemberName m) throws IllegalAccessException { |
916 int allowedModes = this.allowedModes; |
950 int allowedModes = this.allowedModes; |
917 if (allowedModes == TRUSTED) return; |
951 if (allowedModes == TRUSTED) return; |
918 int mods = m.getModifiers(); |
952 int mods = m.getModifiers(); |
919 if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0) |
953 if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0) |
920 return; // common case |
954 return; // common case |
925 return; |
959 return; |
926 if (((requestedModes & ~allowedModes) & PROTECTED) != 0 |
960 if (((requestedModes & ~allowedModes) & PROTECTED) != 0 |
927 && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) |
961 && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) |
928 // Protected members can also be checked as if they were package-private. |
962 // Protected members can also be checked as if they were package-private. |
929 return; |
963 return; |
930 throw newNoAccessException(accessFailedMessage(refc, m), m, lookupClass()); |
964 throw newNoAccessException(accessFailedMessage(refc, m), m, this); |
931 } |
965 } |
932 |
966 |
933 String accessFailedMessage(Class<?> refc, MemberName m) { |
967 String accessFailedMessage(Class<?> refc, MemberName m) { |
934 Class<?> defc = m.getDeclaringClass(); |
968 Class<?> defc = m.getDeclaringClass(); |
935 int mods = m.getModifiers(); |
969 int mods = m.getModifiers(); |
936 if (!VerifyAccess.isClassAccessible(defc, lookupClass())) |
970 // check the class first: |
|
971 boolean classOK = (Modifier.isPublic(defc.getModifiers()) && |
|
972 (defc == refc || |
|
973 Modifier.isPublic(refc.getModifiers()))); |
|
974 if (!classOK && (allowedModes & PACKAGE) != 0) { |
|
975 classOK = (VerifyAccess.isClassAccessible(defc, lookupClass()) && |
|
976 (defc == refc || |
|
977 VerifyAccess.isClassAccessible(refc, lookupClass()))); |
|
978 } |
|
979 if (!classOK) |
937 return "class is not public"; |
980 return "class is not public"; |
938 if (refc != defc && !VerifyAccess.isClassAccessible(refc, lookupClass())) |
|
939 return "symbolic reference "+refc.getName()+" is not public"; |
|
940 if (Modifier.isPublic(mods)) |
981 if (Modifier.isPublic(mods)) |
941 return "access to public member failed"; // (how?) |
982 return "access to public member failed"; // (how?) |
942 else if (allowedModes == PUBLIC) |
|
943 return "member is not public"; |
|
944 else if (allowedModes == 0) |
|
945 return "attempted member access through a non-public class"; |
|
946 if (Modifier.isPrivate(mods)) |
983 if (Modifier.isPrivate(mods)) |
947 return "member is private"; |
984 return "member is private"; |
948 if (Modifier.isProtected(mods)) |
985 if (Modifier.isProtected(mods)) |
949 return "member is protected"; |
986 return "member is protected"; |
950 return "member is private to package"; |
987 return "member is private to package"; |
951 } |
988 } |
952 |
989 |
953 private static final boolean ALLOW_NESTMATE_ACCESS = false; |
990 private static final boolean ALLOW_NESTMATE_ACCESS = false; |
954 |
991 |
955 void checkSpecialCaller(Class<?> specialCaller) throws NoAccessException { |
992 void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException { |
956 if (allowedModes == TRUSTED) return; |
993 if (allowedModes == TRUSTED) return; |
957 if ((allowedModes & PRIVATE) == 0 |
994 if ((allowedModes & PRIVATE) == 0 |
958 || (specialCaller != lookupClass() |
995 || (specialCaller != lookupClass() |
959 && !(ALLOW_NESTMATE_ACCESS && |
996 && !(ALLOW_NESTMATE_ACCESS && |
960 VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) |
997 VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) |
961 throw newNoAccessException("no private access for invokespecial", |
998 throw newNoAccessException("no private access for invokespecial", |
962 new MemberName(specialCaller), lookupClass()); |
999 new MemberName(specialCaller), this); |
963 } |
1000 } |
964 |
1001 |
965 MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws NoAccessException { |
1002 MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException { |
966 // The accessing class only has the right to use a protected member |
1003 // The accessing class only has the right to use a protected member |
967 // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc. |
1004 // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc. |
968 if (!method.isProtected() || method.isStatic() |
1005 if (!method.isProtected() || method.isStatic() |
969 || allowedModes == TRUSTED |
1006 || allowedModes == TRUSTED |
970 || method.getDeclaringClass() == lookupClass() |
1007 || method.getDeclaringClass() == lookupClass() |
986 MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); |
1023 MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); |
987 return fixVarargs(narrowMH, mh); |
1024 return fixVarargs(narrowMH, mh); |
988 } |
1025 } |
989 |
1026 |
990 MethodHandle makeAccessor(Class<?> refc, String name, Class<?> type, |
1027 MethodHandle makeAccessor(Class<?> refc, String name, Class<?> type, |
991 boolean isStatic, boolean isSetter) throws NoAccessException { |
1028 boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException { |
992 MemberName field = resolveOrFail(refc, name, type, isStatic); |
1029 MemberName field = resolveOrFail(refc, name, type, isStatic); |
993 if (isStatic != field.isStatic()) |
1030 if (isStatic != field.isStatic()) |
994 throw newNoAccessException(isStatic |
1031 throw newNoAccessException(isStatic |
995 ? "expected a static field" |
1032 ? "expected a static field" |
996 : "expected a non-static field", |
1033 : "expected a non-static field", |
997 field, lookupClass()); |
1034 field, this); |
998 return makeAccessor(refc, field, false, isSetter); |
1035 return makeAccessor(refc, field, false, isSetter); |
999 } |
1036 } |
1000 |
1037 |
1001 MethodHandle makeAccessor(Class<?> refc, MemberName field, |
1038 MethodHandle makeAccessor(Class<?> refc, MemberName field, |
1002 boolean trusted, boolean isSetter) throws NoAccessException { |
1039 boolean trusted, boolean isSetter) throws IllegalAccessException { |
1003 assert(field.isField()); |
1040 assert(field.isField()); |
1004 if (trusted) |
1041 if (trusted) |
1005 return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |
1042 return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |
1006 checkAccess(refc, field); |
1043 checkAccess(refc, field); |
1007 MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |
1044 MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); |