< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page
*** 1611,10 ***
--- 1611,11 ---
          Lookup(Class<?> lookupClass) {
              this(lookupClass, null, FULL_POWER_MODES);
          }
  
          private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
+             assert lookupClass.isPrimaryType();
              assert prevLookupClass == null || ((allowedModes & MODULE) == 0
                      && prevLookupClass.getModule() != lookupClass.getModule());
              assert !lookupClass.isArray() && !lookupClass.isPrimitive();
              this.lookupClass = lookupClass;
              this.prevLookupClass = prevLookupClass;

*** 2581,10 ***
--- 2582,16 ---
           *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
              MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
+             // resolveOrFail could return a non-static <init> method if present
+             // detect and throw NSME before producing a MethodHandle
+             if (!method.isStatic() && name.equals("<init>")) {
+                 throw new NoSuchMethodException("illegal method name: " + name);
+             }
+ 
              return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerLookup(method));
          }
  
          /**
           * Produces a method handle for a virtual method.

*** 2726,10 ***
--- 2733,17 ---
    ProcessBuilder.class, methodType(void.class, String[].class));
  ProcessBuilder pb = (ProcessBuilder)
    MH_newProcessBuilder.invoke("x", "y", "z");
  assertEquals("[x, y, z]", pb.command().toString());
           * }</pre></blockquote>
+          *
+          * @apiNote
+          * This method does not find a static {@code <init>} factory method as it is invoked
+          * via {@code invokestatic} bytecode as opposed to {@code invokespecial} for an
+          * object constructor.  To look up static {@code <init>} factory method, use
+          * the {@link #findStatic(Class, String, MethodType) findStatic} method.
+          *
           * @param refc the class or interface from which the method is accessed
           * @param type the type of the method, with the receiver argument omitted, and a void return type
           * @return the desired method handle
           * @throws NoSuchMethodException if the constructor does not exist
           * @throws IllegalAccessException if access checking fails

*** 2741,10 ***
--- 2755,13 ---
           */
          public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
              if (refc.isArray()) {
                  throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
              }
+             if (type.returnType() != void.class) {
+                 throw new NoSuchMethodException("Constructors must have void return type: " + refc.getName());
+             }
              String name = "<init>";
              MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
              return getDirectConstructor(refc, ctor);
          }
  

*** 3427,14 ***
           *                                is set and {@code asVarargsCollector} fails
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
              MemberName ctor = new MemberName(c);
!             assert(ctor.isConstructor());
              @SuppressWarnings("deprecation")
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
!             return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
          }
  
          /**
           * Produces a method handle giving read access to a reflected field.
           * The type of the method handle will have a return type of the field's
--- 3444,23 ---
           *                                is set and {@code asVarargsCollector} fails
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
              MemberName ctor = new MemberName(c);
!             assert(ctor.isObjectConstructorOrStaticInitMethod());
              @SuppressWarnings("deprecation")
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
!             Class<?> defc = c.getDeclaringClass();
+             if (ctor.isObjectConstructor()) {
+                 assert(ctor.getReturnType() == void.class);
+                 return lookup.getDirectConstructorNoSecurityManager(defc, ctor);
+             } else {
+                 // static init factory is a static method
+                 assert(ctor.isMethod() && ctor.getReturnType() == defc && ctor.getReferenceKind() == REF_invokeStatic) : ctor.toString();
+                 assert(!MethodHandleNatives.isCallerSensitive(ctor));  // must not be caller-sensitive
+                 return lookup.getDirectMethodNoSecurityManager(ctor.getReferenceKind(), defc, ctor, lookup);
+             }
          }
  
          /**
           * Produces a method handle giving read access to a reflected field.
           * The type of the method handle will have a return type of the field's

*** 3699,12 ***
              return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
          }
  
          /** Check name for an illegal leading "&lt;" character. */
          void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
!             if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
!                 throw new NoSuchMethodException("illegal method name: "+name);
          }
  
          /**
           * Find my trustable caller class if m is a caller sensitive method.
           * If this lookup object has original full privilege access, then the caller class is the lookupClass.
--- 3725,15 ---
              return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
          }
  
          /** Check name for an illegal leading "&lt;" character. */
          void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
!             // "<init>" can only be invoked via invokespecial or it's a static init factory
!             if (name.startsWith("<") && refKind != REF_newInvokeSpecial &&
+                     !(refKind == REF_invokeStatic && name.equals("<init>"))) {
+                     throw new NoSuchMethodException("illegal method name: " + name);
+             }
          }
  
          /**
           * Find my trustable caller class if m is a caller sensitive method.
           * If this lookup object has original full privilege access, then the caller class is the lookupClass.

*** 3804,19 ***
                  smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
              }
  
              // Step 3:
              Class<?> defc = m.getDeclaringClass();
!             if (!fullPrivilegeLookup && defc != refc) {
                  ReflectUtil.checkPackageAccess(defc);
              }
          }
  
          void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
              boolean wantStatic = (refKind == REF_invokeStatic);
              String message;
!             if (m.isConstructor())
                  message = "expected a method, not a constructor";
              else if (!m.isMethod())
                  message = "expected a method";
              else if (wantStatic != m.isStatic())
                  message = wantStatic ? "expected a static method" : "expected a non-static method";
--- 3833,19 ---
                  smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
              }
  
              // Step 3:
              Class<?> defc = m.getDeclaringClass();
!             if (!fullPrivilegeLookup && defc.asPrimaryType() != refc.asPrimaryType()) {
                  ReflectUtil.checkPackageAccess(defc);
              }
          }
  
          void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
              boolean wantStatic = (refKind == REF_invokeStatic);
              String message;
!             if (m.isObjectConstructor())
                  message = "expected a method, not a constructor";
              else if (!m.isMethod())
                  message = "expected a method";
              else if (wantStatic != m.isStatic())
                  message = wantStatic ? "expected a static method" : "expected a non-static method";

*** 3887,16 ***
          String accessFailedMessage(Class<?> refc, MemberName m) {
              Class<?> defc = m.getDeclaringClass();
              int mods = m.getModifiers();
              // check the class first:
              boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
!                                (defc == refc ||
                                  Modifier.isPublic(refc.getModifiers())));
              if (!classOK && (allowedModes & PACKAGE) != 0) {
                  // ignore previous lookup class to check if default package access
                  classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
!                            (defc == refc ||
                              VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
              }
              if (!classOK)
                  return "class is not public";
              if (Modifier.isPublic(mods))
--- 3916,16 ---
          String accessFailedMessage(Class<?> refc, MemberName m) {
              Class<?> defc = m.getDeclaringClass();
              int mods = m.getModifiers();
              // check the class first:
              boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
!                                (defc.asPrimaryType() == refc.asPrimaryType() ||
                                  Modifier.isPublic(refc.getModifiers())));
              if (!classOK && (allowedModes & PACKAGE) != 0) {
                  // ignore previous lookup class to check if default package access
                  classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
!                            (defc.asPrimaryType() == refc.asPrimaryType() ||
                              VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
              }
              if (!classOK)
                  return "class is not public";
              if (Modifier.isPublic(mods))

*** 3969,11 ***
              checkMethod(refKind, refc, method);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, method);
              assert(!method.isMethodHandleInvoke());
- 
              if (refKind == REF_invokeSpecial &&
                  refc != lookupClass() &&
                  !refc.isInterface() &&
                  refc != lookupClass().getSuperclass() &&
                  refc.isAssignableFrom(lookupClass())) {
--- 3998,10 ---

*** 4113,11 ***
              return getDirectConstructorCommon(refc, ctor, checkSecurity);
          }
          /** Common code for all constructors; do not call directly except from immediately above. */
          private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
                                                    boolean checkSecurity) throws IllegalAccessException {
!             assert(ctor.isConstructor());
              checkAccess(REF_newInvokeSpecial, refc, ctor);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, ctor);
              assert(!MethodHandleNatives.isCallerSensitive(ctor));  // maybeBindCaller not relevant here
--- 4141,11 ---
              return getDirectConstructorCommon(refc, ctor, checkSecurity);
          }
          /** Common code for all constructors; do not call directly except from immediately above. */
          private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
                                                    boolean checkSecurity) throws IllegalAccessException {
!             assert(ctor.isObjectConstructor());
              checkAccess(REF_newInvokeSpecial, refc, ctor);
              // Optionally check with the security manager; this isn't needed for unreflect* calls.
              if (checkSecurity)
                  checkSecurityManager(refc, ctor);
              assert(!MethodHandleNatives.isCallerSensitive(ctor));  // maybeBindCaller not relevant here

*** 4292,11 ***
       * The first and second arguments will be the array type and int.
       *
       * <p> When the returned method handle is invoked,
       * the array reference and array index are checked.
       * A {@code NullPointerException} will be thrown if the array reference
!      * is {@code null} and an {@code ArrayIndexOutOfBoundsException} will be
       * thrown if the index is negative or if it is greater than or equal to
       * the length of the array.
       *
       * @param arrayClass the class of an array
       * @return a method handle which can store values into the array type
--- 4320,13 ---
       * The first and second arguments will be the array type and int.
       *
       * <p> When the returned method handle is invoked,
       * the array reference and array index are checked.
       * A {@code NullPointerException} will be thrown if the array reference
!      * is {@code null} or if the array's element type is a {@link Class#isValueType()
+      * a primitive value type} and attempts to set {@code null} in the
+      * array element.  An {@code ArrayIndexOutOfBoundsException} will be
       * thrown if the index is negative or if it is greater than or equal to
       * the length of the array.
       *
       * @param arrayClass the class of an array
       * @return a method handle which can store values into the array type

*** 5064,11 ***
       * @see MethodHandles#explicitCastArguments
       * @since 9
       */
      public static MethodHandle zero(Class<?> type) {
          Objects.requireNonNull(type);
!         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
      }
  
      private static MethodHandle identityOrVoid(Class<?> type) {
          return type == void.class ? zero(type) : identity(type);
      }
--- 5094,17 ---
       * @see MethodHandles#explicitCastArguments
       * @since 9
       */
      public static MethodHandle zero(Class<?> type) {
          Objects.requireNonNull(type);
!         if (type.isPrimitive()) {
+             return zero(Wrapper.forPrimitiveType(type), type);
+         } else if (type.isPrimitiveClass()) {
+             throw new UnsupportedOperationException();
+         } else {
+             return zero(Wrapper.OBJECT, type);
+         }
      }
  
      private static MethodHandle identityOrVoid(Class<?> type) {
          return type == void.class ? zero(type) : identity(type);
      }

*** 5094,11 ***
          return dropArguments(zero(type.returnType()), 0, type.parameterList());
      }
  
      private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
      private static MethodHandle makeIdentity(Class<?> ptype) {
!         MethodType mtype = methodType(ptype, ptype);
          LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
          return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
      }
  
      private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
--- 5130,11 ---
          return dropArguments(zero(type.returnType()), 0, type.parameterList());
      }
  
      private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
      private static MethodHandle makeIdentity(Class<?> ptype) {
!         MethodType mtype = MethodType.methodType(ptype, ptype);
          LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
          return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
      }
  
      private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
< prev index next >