8001109: arity mismatch on a call to spreader method handle should elicit IllegalArgumentException
Summary: Document error conditions that may occur when calling a "spreader" method handle. Use IAE in all cases.
Reviewed-by: twisti, vlivanov
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Sat Oct 05 05:30:39 2013 -0700
@@ -804,6 +804,10 @@
* to the target method handle.
* (The array may also be null when zero elements are required.)
* <p>
+ * If, when the adapter is called, the supplied array argument does
+ * not have the correct number of elements, the adapter will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
+ * <p>
* Here are some simple examples of array-spreading method handles:
* <blockquote><pre>{@code
MethodHandle equals = publicLookup()
@@ -814,6 +818,12 @@
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+ Object[] badArityArgs = (n == 2 ? null : new Object[n]);
+ try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+ catch (IllegalArgumentException ex) { } // OK
+}
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Sat Oct 05 05:30:39 2013 -0700
@@ -460,14 +460,8 @@
}
static void checkSpreadArgument(Object av, int n) {
- // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE
- // but the actual exception raised by an arity mismatch should be WMTE
- final boolean RAISE_RANDOM_EXCEPTIONS = true; // FIXME: delete in JSR 292 M1
if (av == null) {
if (n == 0) return;
- int len;
- if (RAISE_RANDOM_EXCEPTIONS)
- len = ((Object[])av).length; // throw NPE; but delete this after tests are fixed
} else if (av instanceof Object[]) {
int len = ((Object[])av).length;
if (len == n) return;
@@ -476,9 +470,7 @@
if (len == n) return;
}
// fall through to error:
- if (RAISE_RANDOM_EXCEPTIONS)
- throw newIllegalArgumentException("Array is not of length "+n);
- throw new WrongMethodTypeException("Array is not of length "+n);
+ throw newIllegalArgumentException("array is not of length "+n);
}
/**
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Sat Oct 05 05:30:39 2013 -0700
@@ -1511,6 +1511,9 @@
* <p>
* Before invoking its target, the invoker will spread the final array, apply
* reference casts as necessary, and unbox and widen primitive arguments.
+ * If, when the invoker is called, the supplied array argument does
+ * not have the correct number of elements, the invoker will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
--- a/jdk/test/java/lang/invoke/JavaDocExamplesTest.java Sat Oct 05 05:30:39 2013 -0700
+++ b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java Sat Oct 05 05:30:39 2013 -0700
@@ -264,6 +264,12 @@
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+ Object[] badArityArgs = (n == 2 ? null : new Object[n]);
+ try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+ catch (IllegalArgumentException ex) { } // OK
+}
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));