< prev index next >
test/java/lang/invoke/ExplicitCastArgumentsTest.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 19,101 ****
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! package java.lang.invoke;
!
import sun.invoke.util.Wrapper;
! /* @test
* @summary unit tests for MethodHandles.explicitCastArguments()
! *
! * @run main/bootclasspath java.lang.invoke.ExplicitCastArgumentsTest
*/
public class ExplicitCastArgumentsTest {
! private static final boolean VERBOSE = Boolean.getBoolean("verbose");
private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class;
public static void main(String[] args) throws Throwable {
testVarargsCollector();
testRef2Prim();
System.out.println("TEST PASSED");
}
! public static String[] f(String... args) { return args; }
public static void testVarargsCollector() throws Throwable {
MethodType mt = MethodType.methodType(String[].class, String[].class);
! MethodHandle mh = MethodHandles.publicLookup().findStatic(THIS_CLASS, "f", mt);
! mh = MethodHandles.explicitCastArguments(mh, MethodType.methodType(Object.class, Object.class));
! mh.invokeWithArguments((Object)(new String[] {"str1", "str2"}));
}
! public static void testRef2Prim() throws Throwable {
for (Wrapper from : Wrapper.values()) {
for (Wrapper to : Wrapper.values()) {
! if (from == Wrapper.VOID || to == Wrapper.VOID) continue;
! testRef2Prim(from, to);
}
}
}
! public static void testRef2Prim(Wrapper from, Wrapper to) throws Throwable {
! // MHs.eCA javadoc:
! // If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced.
! test(from.wrapperType(), to.primitiveType(), null, false);
}
! public static void test(Class<?> from, Class<?> to, Object param, boolean failureExpected) throws Throwable {
! if (VERBOSE) System.out.printf("%-10s => %-10s: %5s: ", from.getSimpleName(), to.getSimpleName(), param);
! MethodHandle original = MethodHandles.identity(from);
! MethodType newType = original.type().changeReturnType(to);
try {
! MethodHandle target = MethodHandles.explicitCastArguments(original, newType);
! Object result = target.invokeWithArguments(param);
if (VERBOSE) {
String resultStr;
if (result != null) {
! resultStr = String.format("%10s (%10s)", "'"+result+"'", result.getClass().getSimpleName());
} else {
! resultStr = String.format("%10s", result);
}
System.out.println(resultStr);
}
-
if (failureExpected) {
! String msg = String.format("No exception thrown: %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg);
}
} catch (AssertionError e) {
throw e; // report test failure
} catch (Throwable e) {
! if (VERBOSE) System.out.printf("%s: %s\n", e.getClass(), e.getMessage());
! if (!failureExpected) {
! String msg = String.format("Unexpected exception was thrown: %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg, e);
}
}
}
}
--- 19,531 ----
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! import java.io.File;
! import java.lang.invoke.MethodHandle;
! import java.lang.invoke.MethodHandles;
! import java.lang.invoke.MethodType;
! import java.lang.invoke.WrongMethodTypeException;
! import java.net.URL;
! import java.net.URLClassLoader;
! import java.util.HashMap;
! import java.util.Map;
! import java.util.Random;
import sun.invoke.util.Wrapper;
+ import com.oracle.testlibrary.jsr292.Helper;
! /*
! * @test
! * @bug 8060483 8066746
! * @key randomness
! * @library /lib/testlibrary /lib/testlibrary/jsr292
* @summary unit tests for MethodHandles.explicitCastArguments()
! * @run main ExplicitCastArgumentsTest
! */
!
! /**
! * Tests for MethodHandles.explicitCastArguments().
*/
public class ExplicitCastArgumentsTest {
!
! private static final boolean VERBOSE = Helper.IS_VERBOSE;
private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class;
+ private static final Random RNG = Helper.RNG;
+ private static final Map<Wrapper, Object> RANDOM_VALUES = new HashMap<>(9);
+
+ static {
+ RANDOM_VALUES.put(Wrapper.BOOLEAN, RNG.nextBoolean());
+ RANDOM_VALUES.put(Wrapper.BYTE, (byte) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.SHORT, (short) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.CHAR, (char) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.INT, RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.LONG, RNG.nextLong());
+ RANDOM_VALUES.put(Wrapper.FLOAT, RNG.nextFloat());
+ RANDOM_VALUES.put(Wrapper.DOUBLE, RNG.nextDouble());
+ RANDOM_VALUES.put(Wrapper.OBJECT, new Object());
+ }
public static void main(String[] args) throws Throwable {
testVarargsCollector();
+ testNullRef2Prim();
testRef2Prim();
+ testPrim2Ref();
+ testPrim2Prim();
+ testNonBCPRef2Ref();
+ testBCPRef2Ref();
+ testReturnAny2Void();
+ testReturnVoid2Any();
+ testMultipleArgs();
System.out.println("TEST PASSED");
}
! /**
! * Dummy method used in {@link #testVarargsCollector} test to form a method
! * handle.
! *
! * @param args - any args
! * @return - returns args
! */
! public static String[] f(String... args) {
! return args;
! }
+ /**
+ * Tests that MHs.explicitCastArguments does incorrect type checks for
+ * VarargsCollector. Bug 8066746.
+ *
+ * @throws java.lang.Throwable
+ */
public static void testVarargsCollector() throws Throwable {
MethodType mt = MethodType.methodType(String[].class, String[].class);
! MethodHandle mh = MethodHandles.publicLookup()
! .findStatic(THIS_CLASS, "f", mt);
! mh = MethodHandles.explicitCastArguments(mh,
! MethodType.methodType(Object.class, Object.class));
! mh.invokeWithArguments((Object) (new String[]{"str1", "str2"}));
}
! /**
! * Tests that null wrapper reference is successfully converted to primitive
! * types. Converted result should be zero for a primitive. Bug 8060483.
! */
! public static void testNullRef2Prim() {
for (Wrapper from : Wrapper.values()) {
for (Wrapper to : Wrapper.values()) {
! if (from == Wrapper.VOID || to == Wrapper.VOID) {
! continue;
! }
! // MHs.eCA javadoc:
! // If T0 is a reference and T1 a primitive, and if the reference
! // is null at runtime, a zero value is introduced.
! for (TestConversionMode mode : TestConversionMode.values()) {
! testConversion(mode, from.wrapperType(),
! to.primitiveType(), null, to.zero(), false, null);
! }
}
}
}
! /**
! * Tests that non-null wrapper reference is successfully converted to
! * primitive types.
! */
! public static void testRef2Prim() {
! for (Wrapper from : Wrapper.values()) {
! for (Wrapper to : Wrapper.values()) {
! if (from == Wrapper.VOID || to == Wrapper.VOID
! || to == Wrapper.OBJECT) {
! continue;
! }
! Object value = RANDOM_VALUES.get(from);
! for (TestConversionMode mode : TestConversionMode.values()) {
! if (from != Wrapper.OBJECT) {
! Object convValue = to.wrap(value);
! testConversion(mode, from.wrapperType(),
! to.primitiveType(), value, convValue, false, null);
! } else {
! testConversion(mode, from.wrapperType(),
! to.primitiveType(), value, null,
! true, ClassCastException.class);
! }
! }
! }
! }
! }
!
! /**
! * Tests that primitive is successfully converted to wrapper reference
! * types, to the Number type (if possible) and to the Object type.
! */
! public static void testPrim2Ref() {
! for (Wrapper from : Wrapper.values()) {
! for (Wrapper to : Wrapper.values()) {
! if (from == Wrapper.VOID || from == Wrapper.OBJECT
! || to == Wrapper.VOID || to == Wrapper.OBJECT) {
! continue;
! }
! Object value = RANDOM_VALUES.get(from);
! for (TestConversionMode mode : TestConversionMode.values()) {
! if (from == to) {
! testConversion(mode, from.primitiveType(),
! to.wrapperType(), value, value, false, null);
! } else {
! testConversion(mode, from.primitiveType(),
! to.wrapperType(), value, null, true, ClassCastException.class);
! }
! if (from != Wrapper.BOOLEAN && from != Wrapper.CHAR) {
! testConversion(mode, from.primitiveType(),
! Number.class, value, value, false, null);
! } else {
! testConversion(mode, from.primitiveType(),
! Number.class, value, null,
! true, ClassCastException.class);
! }
! testConversion(mode, from.primitiveType(),
! Object.class, value, value, false, null);
! }
! }
! }
! }
!
! /**
! * Tests that primitive is successfully converted to other primitive type.
! */
! public static void testPrim2Prim() {
! for (Wrapper from : Wrapper.values()) {
! for (Wrapper to : Wrapper.values()) {
! if (from == Wrapper.VOID || to == Wrapper.VOID
! || from == Wrapper.OBJECT || to == Wrapper.OBJECT) {
! continue;
! }
! Object value = RANDOM_VALUES.get(from);
! Object convValue = to.wrap(value);
! for (TestConversionMode mode : TestConversionMode.values()) {
! testConversion(mode, from.primitiveType(),
! to.primitiveType(), value, convValue, false, null);
! }
! }
! }
! }
!
! /**
! * Dummy interface for {@link #testNonBCPRef2Ref} test.
! */
! public static interface TestInterface {}
!
! /**
! * Dummy class for {@link #testNonBCPRef2Ref} test.
! */
! public static class TestSuperClass implements TestInterface {}
!
! /**
! * Dummy class for {@link #testNonBCPRef2Ref} test.
! */
! public static class TestSubClass1 extends TestSuperClass {}
!
! /**
! * Dummy class for {@link #testNonBCPRef2Ref} test.
! */
! public static class TestSubClass2 extends TestSuperClass {}
!
! /**
! * Tests non-bootclasspath reference to reference conversions.
! *
! * @throws java.lang.Throwable
! */
! public static void testNonBCPRef2Ref() throws Throwable {
! String testClassPath = System.getProperty("test.classes",".");
! URL[] classpath = {(new File(testClassPath)).getCanonicalFile()
! .toURI().toURL()};
! URLClassLoader ucl = URLClassLoader.newInstance(classpath);
! Class testInterface = ucl.loadClass(THIS_CLASS.getSimpleName()
! + "$TestInterface");
! Class testSuperClass = ucl.loadClass(THIS_CLASS.getSimpleName()
! + "$TestSuperClass");
! Class testSubClass1 = ucl.loadClass(THIS_CLASS.getSimpleName()
! + "$TestSubClass1");
! Class testSubClass2 = TestSubClass2.class;
! Object testSuperObj = testSuperClass.newInstance();
! Object testObj01 = testSubClass1.newInstance();
! Object testObj02 = new TestSubClass2();
! Class[] parents = {testInterface, testSuperClass};
! Class[] children = {testSubClass1, testSubClass2};
! Object[] childInst = {testObj01, testObj02};
! for (TestConversionMode mode : TestConversionMode.values()) {
! for (int i = 0; i < parents.length; i++) {
! for (int j = 0; j < children.length; j++) {
! // Child type to parent type non-null conversion, shoud succeed
! testConversion(mode, children[i], parents[j], childInst[i],
! childInst[i], false, null);
! // Child type to parent type null conversion, shoud succeed
! testConversion(mode, children[i], parents[j], null,
! null, false, null);
! // Parent type to child type non-null conversion with parent
! // type instance, should fail
! testConversion(mode, parents[i],
! children[j], testSuperObj, null, true,
! ClassCastException.class);
! // Parent type to child type non-null conversion with child
! // type instance, should succeed
! testConversion(mode, parents[i],
! children[j], childInst[j], childInst[j], false, null);
! // Parent type to child type null conversion, should succeed
! testConversion(mode, parents[i],
! children[j], null, null, false, null);
! }
! // Parent type to child type non-null conversion with sibling
! // type instance, should fail
! testConversion(mode, parents[i], testSubClass1, testObj02,
! null, true, ClassCastException.class);
! }
! // Sibling type non-null conversion, should fail
! testConversion(mode, testSubClass1,
! testSubClass2, testObj01, null, true,
! ClassCastException.class);
! // Sibling type null conversion, should succeed
! testConversion(mode, testSubClass1,
! testSubClass2, null, null, false, null);
! }
! }
!
! /**
! * Tests bootclasspath reference to reference conversions.
! */
! public static void testBCPRef2Ref() {
! Class bcpInterface = CharSequence.class;
! Class bcpSubClass1 = String.class;
! Class bcpSubClass2 = StringBuffer.class;
! Object testObj01 = new String("test");
! Object testObj02 = new StringBuffer("test");
! Class[] children = {bcpSubClass1, bcpSubClass2};
! Object[] childInst = {testObj01, testObj02};
! for (TestConversionMode mode : TestConversionMode.values()) {
! for (int i = 0; i < children.length; i++) {
! // Child type to parent type non-null conversion, shoud succeed
! testConversion(mode, children[i], bcpInterface, childInst[i],
! childInst[i], false, null);
! // Child type to parent type null conversion, shoud succeed
! testConversion(mode, children[i], bcpInterface, null,
! null, false, null);
! // Parent type to child type non-null conversion with child
! // type instance, should succeed
! testConversion(mode, bcpInterface,
! children[i], childInst[i], childInst[i], false, null);
! // Parent type to child type null conversion, should succeed
! testConversion(mode, bcpInterface,
! children[i], null, null, false, null);
! }
! // Sibling type non-null conversion, should fail
! testConversion(mode, bcpSubClass1,
! bcpSubClass2, testObj01, null, true,
! ClassCastException.class);
! // Sibling type null conversion, should succeed
! testConversion(mode, bcpSubClass1,
! bcpSubClass2, null, null, false, null);
! // Parent type to child type non-null conversion with sibling
! // type instance, should fail
! testConversion(mode, bcpInterface, bcpSubClass1, testObj02,
! null, true, ClassCastException.class);
! }
}
! /**
! * Dummy method used in {@link #testReturnAny2Void} and
! * {@link #testReturnVoid2Any} tests to form a method handle.
! */
! public static void retVoid() {}
! /**
! * Tests that non-null any return is successfully converted to non-type
! * void.
! */
! public static void testReturnAny2Void() {
! for (Wrapper from : Wrapper.values()) {
! testConversion(TestConversionMode.RETURN_VALUE, from.wrapperType(),
! void.class, RANDOM_VALUES.get(from),
! null, false, null);
! testConversion(TestConversionMode.RETURN_VALUE, from.primitiveType(),
! void.class, RANDOM_VALUES.get(from),
! null, false, null);
! }
! }
+ /**
+ * Tests that void return is successfully converted to primitive and
+ * reference. Result should be zero for primitives and null for references.
+ */
+ public static void testReturnVoid2Any() {
+ for (Wrapper to : Wrapper.values()) {
+ testConversion(TestConversionMode.RETURN_VALUE, void.class,
+ to.primitiveType(), null,
+ to.zero(), false, null);
+ testConversion(TestConversionMode.RETURN_VALUE, void.class,
+ to.wrapperType(), null,
+ null, false, null);
+ }
+ }
+
+ private static void checkForWrongMethodTypeException(MethodHandle mh, MethodType mt) {
try {
! MethodHandles.explicitCastArguments(mh, mt);
! throw new AssertionError("Expected WrongMethodTypeException is not thrown");
! } catch (WrongMethodTypeException wmte) {
! if (VERBOSE) {
! System.out.printf("Expected exception %s: %s\n",
! wmte.getClass(), wmte.getMessage());
! }
! }
! }
+ /**
+ * Tests that MHs.eCA method works correctly with MHs with multiple arguments.
+ * @throws Throwable
+ */
+ public static void testMultipleArgs() throws Throwable {
+ int arity = 1 + RNG.nextInt(Helper.MAX_ARITY / 2 - 2);
+ int arityMinus = RNG.nextInt(arity);
+ int arityPlus = arity + RNG.nextInt(Helper.MAX_ARITY / 2 - arity) + 1;
+ MethodType mType = Helper.randomMethodTypeGenerator(arity);
+ MethodType mTypeNew = Helper.randomMethodTypeGenerator(arity);
+ MethodType mTypeNewMinus = Helper.randomMethodTypeGenerator(arityMinus);
+ MethodType mTypeNewPlus = Helper.randomMethodTypeGenerator(arityPlus);
+ Class<?> rType = mType.returnType();
+ MethodHandle original;
+ if (rType.equals(void.class)) {
+ MethodType mt = MethodType.methodType(void.class);
+ original = MethodHandles.publicLookup()
+ .findStatic(THIS_CLASS, "retVoid", mt);
+ } else {
+ Object rValue = Helper.castToWrapper(1, rType);
+ original = MethodHandles.constant(rType, rValue);
+ }
+ original = Helper.addTrailingArgs(original, arity, mType.parameterList());
+ MethodHandle target = MethodHandles
+ .explicitCastArguments(original, mTypeNew);
+ Object[] parList = Helper.randomArgs(mTypeNew.parameterList());
+ for (int i = 0; i < parList.length; i++) {
+ if (parList[i] instanceof String) {
+ parList[i] = null; //getting rid of Stings produced by randomArgs
+ }
+ }
+ target.invokeWithArguments(parList);
+ checkForWrongMethodTypeException(original, mTypeNewMinus);
+ checkForWrongMethodTypeException(original, mTypeNewPlus);
+ }
+
+ /**
+ * Enumeration of test conversion modes.
+ */
+ public enum TestConversionMode {
+ RETURN_VALUE,
+ ARGUMENT;
+ }
+
+ /**
+ * Tests type and value conversion. Comparing with the given expected result.
+ *
+ * @param mode - test conversion mode. See {@link #TestConversionMode}.
+ * @param from - source type.
+ * @param to - destination type.
+ * @param param - value to be converted.
+ * @param expectedResult - expected value after conversion.
+ * @param failureExpected - true if conversion failure expected.
+ * @param expectedException - expected exception class if
+ * {@code failureExpected} is true.
+ */
+ public static void testConversion(TestConversionMode mode,
+ Class<?> from, Class<?> to, Object param,
+ Object expectedResult, boolean failureExpected,
+ Class<? extends Throwable> expectedException) {
+ if (VERBOSE) {
+ System.out.printf("Testing return value conversion: "
+ + "%-10s => %-10s: %5s: ", from.getSimpleName(),
+ to.getSimpleName(), param);
+ }
+ MethodHandle original = null;
+ MethodType newType = null;
+ switch (mode) {
+ case RETURN_VALUE:
+ if (from.equals(void.class)) {
+ MethodType mt = MethodType.methodType(void.class);
+ try {
+ original = MethodHandles.publicLookup()
+ .findStatic(THIS_CLASS, "retVoid", mt);
+ } catch (NoSuchMethodException | IllegalAccessException ex) {
+ throw new Error("Unexpected issue", ex);
+ }
+ } else {
+ original = MethodHandles.constant(from, param);
+ }
+ newType = original.type().changeReturnType(to);
+ break;
+ case ARGUMENT:
+ if (from.equals(void.class) || to.equals(void.class)) {
+ throw new Error("Test issue: argument conversion does not"
+ + " work with non-type void");
+ }
+ original = MethodHandles.identity(to);
+ newType = original.type().changeParameterType(0, from);
+ break;
+ default:
+ String msg = String.format("Test issue: unknown test"
+ + " convertion mode %s.", mode.name());
+ throw new Error(msg);
+ }
+ try {
+ MethodHandle target = MethodHandles
+ .explicitCastArguments(original, newType);
+ Object result;
+ switch (mode) {
+ case RETURN_VALUE:
+ result = target.invokeWithArguments();
+ break;
+ case ARGUMENT:
+ result = target.invokeWithArguments(param);
+ break;
+ default:
+ String msg = String.format("Test issue: unknown test"
+ + " convertion mode %s.", mode.name());
+ throw new Error(msg);
+ }
+ if (!failureExpected
+ && (expectedResult != null && !expectedResult.equals(result)
+ || expectedResult == null && result != null)) {
+ String msg = String.format("Conversion result %s is not equal"
+ + " to the expected result %10s",
+ result, expectedResult);
+ throw new AssertionError(msg);
+ }
if (VERBOSE) {
String resultStr;
if (result != null) {
! resultStr = String.format("Converted value and type are"
! + " %10s (%10s)", "'" + result + "'",
! result.getClass().getSimpleName());
} else {
! resultStr = String.format("Converted value is %10s", result);
}
System.out.println(resultStr);
}
if (failureExpected) {
! String msg = String.format("No exception thrown while testing"
! + " return value conversion: %10s => %10s;"
! + " parameter: %10s",
! from, to, param);
throw new AssertionError(msg);
}
} catch (AssertionError e) {
throw e; // report test failure
} catch (Throwable e) {
! if (VERBOSE) {
! System.out.printf("%s: %s\n", e.getClass(), e.getMessage());
! }
! if (!failureExpected || !e.getClass().equals(expectedException)) {
! String msg = String.format("Unexpected exception was thrown"
! + " while testing return value conversion:"
! + " %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg, e);
}
}
}
}
< prev index next >