850 assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
851 * }</pre></blockquote>
852 * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
853 * @param arrayLength the number of arguments to spread from an incoming array argument
854 * @return a new method handle which spreads its final array argument,
855 * before calling the original method handle
856 * @throws NullPointerException if {@code arrayType} is a null reference
857 * @throws IllegalArgumentException if {@code arrayType} is not an array type,
858 * or if target does not have at least
859 * {@code arrayLength} parameter types,
860 * or if {@code arrayLength} is negative,
861 * or if the resulting method handle's type would have
862 * <a href="MethodHandle.html#maxarity">too many parameters</a>
863 * @throws WrongMethodTypeException if the implied {@code asType} call fails
864 * @see #asCollector
865 */
866 public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
867 MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
868 int arity = type().parameterCount();
869 int spreadArgPos = arity - arrayLength;
870 if (USE_LAMBDA_FORM_EDITOR) {
871 MethodHandle afterSpread = this.asType(postSpreadType);
872 BoundMethodHandle mh = afterSpread.rebind();
873 LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
874 MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
875 return mh.copyWith(preSpreadType, lform);
876 } else {
877 return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
878 }
879 }
880
881 /**
882 * See if {@code asSpreader} can be validly called with the given arguments.
883 * Return the type of the method handle call after spreading but before conversions.
884 */
885 private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
886 spreadArrayChecks(arrayType, arrayLength);
887 int nargs = type().parameterCount();
888 if (nargs < arrayLength || arrayLength < 0)
889 throw newIllegalArgumentException("bad spread array length");
890 Class<?> arrayElement = arrayType.getComponentType();
891 MethodType mtype = type();
892 boolean match = true, fail = false;
893 for (int i = nargs - arrayLength; i < nargs; i++) {
894 Class<?> ptype = mtype.parameterType(i);
895 if (ptype != arrayElement) {
896 match = false;
897 if (!MethodType.canConvert(arrayElement, ptype)) {
898 fail = true;
979 .asCollector(long[].class, 1);
980 assertEquals("[123]", (String) longsToString.invokeExact((long)123));
981 * }</pre></blockquote>
982 * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
983 * @param arrayLength the number of arguments to collect into a new array argument
984 * @return a new method handle which collects some trailing argument
985 * into an array, before calling the original method handle
986 * @throws NullPointerException if {@code arrayType} is a null reference
987 * @throws IllegalArgumentException if {@code arrayType} is not an array type
988 * or {@code arrayType} is not assignable to this method handle's trailing parameter type,
989 * or {@code arrayLength} is not a legal array size,
990 * or the resulting method handle's type would have
991 * <a href="MethodHandle.html#maxarity">too many parameters</a>
992 * @throws WrongMethodTypeException if the implied {@code asType} call fails
993 * @see #asSpreader
994 * @see #asVarargsCollector
995 */
996 public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
997 asCollectorChecks(arrayType, arrayLength);
998 int collectArgPos = type().parameterCount() - 1;
999 if (USE_LAMBDA_FORM_EDITOR) {
1000 BoundMethodHandle mh = rebind();
1001 MethodType resultType = type().asCollectorType(arrayType, arrayLength);
1002 MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
1003 LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
1004 if (lform != null) {
1005 return mh.copyWith(resultType, lform);
1006 }
1007 lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
1008 return mh.copyWithExtendL(resultType, lform, newArray);
1009 } else {
1010 MethodHandle target = this;
1011 if (arrayType != type().parameterType(collectArgPos))
1012 target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true);
1013 MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
1014 return MethodHandles.collectArguments(target, collectArgPos, collector);
1015 }
1016 }
1017
1018 /**
1019 * See if {@code asCollector} can be validly called with the given arguments.
1020 * Return false if the last parameter is not an exact match to arrayType.
1021 */
1022 /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
1023 spreadArrayChecks(arrayType, arrayLength);
1024 int nargs = type().parameterCount();
1025 if (nargs != 0) {
1026 Class<?> lastParam = type().parameterType(nargs-1);
1027 if (lastParam == arrayType) return true;
1028 if (lastParam.isAssignableFrom(arrayType)) return false;
1029 }
1030 throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
1031 }
1032
1033 /**
1034 * Makes a <em>variable arity</em> adapter which is able to accept
1035 * any number of trailing positional arguments and collect them
|
850 assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
851 * }</pre></blockquote>
852 * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
853 * @param arrayLength the number of arguments to spread from an incoming array argument
854 * @return a new method handle which spreads its final array argument,
855 * before calling the original method handle
856 * @throws NullPointerException if {@code arrayType} is a null reference
857 * @throws IllegalArgumentException if {@code arrayType} is not an array type,
858 * or if target does not have at least
859 * {@code arrayLength} parameter types,
860 * or if {@code arrayLength} is negative,
861 * or if the resulting method handle's type would have
862 * <a href="MethodHandle.html#maxarity">too many parameters</a>
863 * @throws WrongMethodTypeException if the implied {@code asType} call fails
864 * @see #asCollector
865 */
866 public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
867 MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
868 int arity = type().parameterCount();
869 int spreadArgPos = arity - arrayLength;
870 MethodHandle afterSpread = this.asType(postSpreadType);
871 BoundMethodHandle mh = afterSpread.rebind();
872 LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
873 MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
874 return mh.copyWith(preSpreadType, lform);
875 }
876
877 /**
878 * See if {@code asSpreader} can be validly called with the given arguments.
879 * Return the type of the method handle call after spreading but before conversions.
880 */
881 private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
882 spreadArrayChecks(arrayType, arrayLength);
883 int nargs = type().parameterCount();
884 if (nargs < arrayLength || arrayLength < 0)
885 throw newIllegalArgumentException("bad spread array length");
886 Class<?> arrayElement = arrayType.getComponentType();
887 MethodType mtype = type();
888 boolean match = true, fail = false;
889 for (int i = nargs - arrayLength; i < nargs; i++) {
890 Class<?> ptype = mtype.parameterType(i);
891 if (ptype != arrayElement) {
892 match = false;
893 if (!MethodType.canConvert(arrayElement, ptype)) {
894 fail = true;
975 .asCollector(long[].class, 1);
976 assertEquals("[123]", (String) longsToString.invokeExact((long)123));
977 * }</pre></blockquote>
978 * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
979 * @param arrayLength the number of arguments to collect into a new array argument
980 * @return a new method handle which collects some trailing argument
981 * into an array, before calling the original method handle
982 * @throws NullPointerException if {@code arrayType} is a null reference
983 * @throws IllegalArgumentException if {@code arrayType} is not an array type
984 * or {@code arrayType} is not assignable to this method handle's trailing parameter type,
985 * or {@code arrayLength} is not a legal array size,
986 * or the resulting method handle's type would have
987 * <a href="MethodHandle.html#maxarity">too many parameters</a>
988 * @throws WrongMethodTypeException if the implied {@code asType} call fails
989 * @see #asSpreader
990 * @see #asVarargsCollector
991 */
992 public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
993 asCollectorChecks(arrayType, arrayLength);
994 int collectArgPos = type().parameterCount() - 1;
995 BoundMethodHandle mh = rebind();
996 MethodType resultType = type().asCollectorType(arrayType, arrayLength);
997 MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
998 LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
999 if (lform != null) {
1000 return mh.copyWith(resultType, lform);
1001 }
1002 lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
1003 return mh.copyWithExtendL(resultType, lform, newArray);
1004 }
1005
1006 /**
1007 * See if {@code asCollector} can be validly called with the given arguments.
1008 * Return false if the last parameter is not an exact match to arrayType.
1009 */
1010 /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
1011 spreadArrayChecks(arrayType, arrayLength);
1012 int nargs = type().parameterCount();
1013 if (nargs != 0) {
1014 Class<?> lastParam = type().parameterType(nargs-1);
1015 if (lastParam == arrayType) return true;
1016 if (lastParam.isAssignableFrom(arrayType)) return false;
1017 }
1018 throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
1019 }
1020
1021 /**
1022 * Makes a <em>variable arity</em> adapter which is able to accept
1023 * any number of trailing positional arguments and collect them
|