Path: blob/master/test/jdk/java/lang/invoke/ExplicitCastArgumentsTest.java
41149 views
/*1* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import sun.invoke.util.Wrapper;24import test.java.lang.invoke.lib.Helper;2526import java.io.File;27import java.io.Serializable;28import java.lang.invoke.MethodHandle;29import java.lang.invoke.MethodHandles;30import java.lang.invoke.MethodType;31import java.lang.invoke.WrongMethodTypeException;32import java.util.HashMap;33import java.util.Map;34import java.util.Random;3536/*37* @test38* @bug 8060483 806674639* @key randomness40* @library /test/lib /java/lang/invoke/common41* @modules java.base/sun.invoke.util42* @summary unit tests for MethodHandles.explicitCastArguments()43* @run main ExplicitCastArgumentsTest44*/4546/**47* Tests for MethodHandles.explicitCastArguments().48*/49public class ExplicitCastArgumentsTest {5051private static final boolean VERBOSE = Helper.IS_VERBOSE;52private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class;53private static final Random RNG = Helper.RNG;54private static final Map<Wrapper, Object> RANDOM_VALUES = new HashMap<>(9);5556static {57RANDOM_VALUES.put(Wrapper.BOOLEAN, RNG.nextBoolean());58RANDOM_VALUES.put(Wrapper.BYTE, (byte) RNG.nextInt());59RANDOM_VALUES.put(Wrapper.SHORT, (short) RNG.nextInt());60RANDOM_VALUES.put(Wrapper.CHAR, (char) RNG.nextInt());61RANDOM_VALUES.put(Wrapper.INT, RNG.nextInt());62RANDOM_VALUES.put(Wrapper.LONG, RNG.nextLong());63RANDOM_VALUES.put(Wrapper.FLOAT, RNG.nextFloat());64RANDOM_VALUES.put(Wrapper.DOUBLE, RNG.nextDouble());65RANDOM_VALUES.put(Wrapper.OBJECT, new Object());66}6768public static void main(String[] args) throws Throwable {69testVarargsCollector();70testNullRef2Prim();71testRef2Prim();72testPrim2Ref();73testPrim2Prim();74testNonBCPRef2NonBCPRef();75testBCPRef2BCPRef();76testNonBCPRef2BCPRef();77testReturnAny2Void();78testReturnVoid2Any();79testMultipleArgs();80System.out.println("TEST PASSED");81}8283/**84* Dummy method used in {@link #testVarargsCollector} test to form a method85* handle.86*87* @param args - any args88* @return - returns args89*/90public static String[] f(String... args) {91return args;92}9394/**95* Tests that MHs.explicitCastArguments does incorrect type checks for96* VarargsCollector. Bug 8066746.97*98* @throws java.lang.Throwable99*/100public static void testVarargsCollector() throws Throwable {101MethodType mt = MethodType.methodType(String[].class, String[].class);102MethodHandle mh = MethodHandles.publicLookup()103.findStatic(THIS_CLASS, "f", mt);104mh = MethodHandles.explicitCastArguments(mh,105MethodType.methodType(Object.class, Object.class));106mh.invokeWithArguments((Object) (new String[]{"str1", "str2"}));107}108109/**110* Tests that null wrapper reference is successfully converted to primitive111* types. Converted result should be zero for a primitive. Bug 8060483.112*/113public static void testNullRef2Prim() {114for (Wrapper from : Wrapper.values()) {115for (Wrapper to : Wrapper.values()) {116if (from == Wrapper.VOID || to == Wrapper.VOID) {117continue;118}119// MHs.eCA javadoc:120// If T0 is a reference and T1 a primitive, and if the reference121// is null at runtime, a zero value is introduced.122for (TestConversionMode mode : TestConversionMode.values()) {123testConversion(mode, from.wrapperType(),124to.primitiveType(), null, to.zero(), false, null);125}126}127}128}129130/**131* Tests that non-null wrapper reference is successfully converted to132* primitive types.133*/134public static void testRef2Prim() {135for (Wrapper from : Wrapper.values()) {136for (Wrapper to : Wrapper.values()) {137if (from == Wrapper.VOID || to == Wrapper.VOID138|| to == Wrapper.OBJECT) {139continue;140}141Object value = RANDOM_VALUES.get(from);142for (TestConversionMode mode : TestConversionMode.values()) {143if (from != Wrapper.OBJECT) {144Object convValue = to.wrap(value);145testConversion(mode, from.wrapperType(),146to.primitiveType(), value, convValue, false, null);147} else {148testConversion(mode, from.wrapperType(),149to.primitiveType(), value, null,150true, ClassCastException.class);151}152}153}154}155}156157/**158* Tests that primitive is successfully converted to wrapper reference159* types, to the Number type (if possible) and to the Object type.160*/161public static void testPrim2Ref() {162for (Wrapper from : Wrapper.values()) {163for (Wrapper to : Wrapper.values()) {164if (from == Wrapper.VOID || from == Wrapper.OBJECT165|| to == Wrapper.VOID || to == Wrapper.OBJECT) {166continue;167}168Object value = RANDOM_VALUES.get(from);169for (TestConversionMode mode : TestConversionMode.values()) {170if (from == to) {171testConversion(mode, from.primitiveType(),172to.wrapperType(), value, value, false, null);173} else {174testConversion(mode, from.primitiveType(),175to.wrapperType(), value, null, true, ClassCastException.class);176}177if (from != Wrapper.BOOLEAN && from != Wrapper.CHAR) {178testConversion(mode, from.primitiveType(),179Number.class, value, value, false, null);180} else {181testConversion(mode, from.primitiveType(),182Number.class, value, null,183true, ClassCastException.class);184}185testConversion(mode, from.primitiveType(),186Object.class, value, value, false, null);187}188}189}190}191192/**193* Tests that primitive is successfully converted to other primitive type.194*/195public static void testPrim2Prim() {196for (Wrapper from : Wrapper.values()) {197for (Wrapper to : Wrapper.values()) {198if (from == Wrapper.VOID || to == Wrapper.VOID199|| from == Wrapper.OBJECT || to == Wrapper.OBJECT) {200continue;201}202Object value = RANDOM_VALUES.get(from);203Object convValue = to.wrap(value);204for (TestConversionMode mode : TestConversionMode.values()) {205testConversion(mode, from.primitiveType(),206to.primitiveType(), value, convValue, false, null);207}208}209}210}211212/**213* Dummy interface for {@link #testNonBCPRef2Ref} test.214*/215public static interface TestInterface {}216217/**218* Dummy class for {@link #testNonBCPRef2Ref} test.219*/220public static class TestSuperClass implements TestInterface {}221222/**223* Dummy class for {@link #testNonBCPRef2Ref} test.224*/225public static class TestSubClass1 extends TestSuperClass {}226227/**228* Dummy class for {@link #testNonBCPRef2Ref} test.229*/230public static class TestSubClass2 extends TestSuperClass {}231232/**233* Tests non-bootclasspath reference to reference conversions.234*235* @throws java.lang.Throwable236*/237public static void testNonBCPRef2NonBCPRef() throws Throwable {238Class testInterface = TestInterface.class;239Class testSuperClass = TestSuperClass.class;240Class testSubClass1 = TestSubClass1.class;241Class testSubClass2 = TestSubClass2.class;242Object testSuperObj = new TestSuperClass();243Object testObj01 = new TestSubClass1();244Object testObj02 = new TestSubClass2();245Class[] parents = {testInterface, testSuperClass};246Class[] children = {testSubClass1, testSubClass2};247Object[] childInst = {testObj01, testObj02};248for (TestConversionMode mode : TestConversionMode.values()) {249for (Class parent : parents) {250for (int j = 0; j < children.length; j++) {251// Child type to parent type non-null conversion, shoud succeed252testConversion(mode, children[j], parent, childInst[j],253childInst[j], false, null);254// Child type to parent type null conversion, shoud succeed255testConversion(mode, children[j], parent, null,256null, false, null);257// Parent type to child type non-null conversion with parent258// type instance, should fail259testConversion(mode, parent, children[j], testSuperObj,260null, true, ClassCastException.class);261// Parent type to child type non-null conversion with child262// type instance, should succeed263testConversion(mode, parent, children[j], childInst[j],264childInst[j], false, null);265// Parent type to child type null conversion, should succeed266testConversion(mode, parent, children[j], null,267null, false, null);268}269// Parent type to child type non-null conversion with sibling270// type instance, should fail271testConversion(mode, parent, testSubClass1, testObj02,272null, true, ClassCastException.class);273}274// Sibling type non-null conversion, should fail275testConversion(mode, testSubClass1,276testSubClass2, testObj01, null, true,277ClassCastException.class);278// Sibling type null conversion, should succeed279testConversion(mode, testSubClass1,280testSubClass2, null, null, false, null);281}282}283284/**285* Dummy interface for {@link #testNonBCPRef2BCPRef} test.286*/287public static interface TestSerializableInterface extends Serializable {}288289/**290* Dummy class for {@link #testNonBCPRef2BCPRef} test.291*/292public static class TestSerializableClass293implements TestSerializableInterface {}294295/**296* Dummy class for {@link #testNonBCPRef2BCPRef} test.297*/298public static class TestFileChildClass extends File299implements TestSerializableInterface {300public TestFileChildClass(String pathname) {301super(pathname);302}303}304305/**306* Tests non-bootclasspath reference to bootclasspath reference conversions307* and vice-versa.308*309* @throws java.lang.Throwable310*/311public static void testNonBCPRef2BCPRef() throws Throwable {312Class bcpInterface = Serializable.class;313Class bcpSuperClass = File.class;314Class nonBcpInterface = TestSerializableInterface.class;315Class nonBcpSuperSiblingClass = TestSerializableClass.class;316Class nonBcpSubClass = TestFileChildClass.class;317Object bcpSuperObj = new File(".");318Object testSuperSiblingObj = new TestSerializableClass();319Object testSubObj = new TestFileChildClass(".");320Class[] parents = {bcpInterface, bcpSuperClass};321for (TestConversionMode mode : TestConversionMode.values()) {322for (Class parent : parents) {323// Child type to parent type non-null conversion, shoud succeed324testConversion(mode, nonBcpSubClass, parent, testSubObj,325testSubObj, false, null);326// Child type to parent type null conversion, shoud succeed327testConversion(mode, nonBcpSubClass, parent, null, null,328false, null);329// Parent type to child type non-null conversion with parent330// type instance, should fail331testConversion(mode, parent, nonBcpSubClass, bcpSuperObj, null,332true, ClassCastException.class);333// Parent type to child type non-null conversion with child334// type instance, should succeed335testConversion(mode, parent, nonBcpSubClass, testSubObj,336testSubObj, false, null);337// Parent type to child type null conversion, should succeed338testConversion(mode, parent, nonBcpSubClass, null, null,339false, null);340}341// Parent type to child type non-null conversion with342// super sibling type instance, should fail343testConversion(mode, bcpInterface, nonBcpSubClass,344testSuperSiblingObj, null, true, ClassCastException.class);345Class[] siblings = {nonBcpSubClass, bcpSuperClass};346for (Class sibling : siblings) {347// Non-bcp class to bcp/non-bcp sibling class non-null348// conversion with nonBcpSuperSiblingClass instance, should fail349testConversion(mode, nonBcpSuperSiblingClass, sibling,350testSuperSiblingObj, null, true, ClassCastException.class);351// Non-bcp class to bcp/non-bcp sibling class null conversion,352// should succeed353testConversion(mode, nonBcpSuperSiblingClass, sibling,354null, null, false, null);355// Non-bcp interface to bcp/non-bcp sibling class non-null356// conversion with nonBcpSubClass instance, should succeed357testConversion(mode, nonBcpInterface, sibling, testSubObj,358testSubObj, false, null);359// Non-bcp interface to bcp/non-bcp sibling class360// null conversion, should succeed361testConversion(mode, nonBcpInterface, sibling, null, null,362false, null);363// Non-bcp interface to bcp/non-bcp sibling class non-null364// conversion with nonBcpSuperSiblingClass instance, should fail365testConversion(mode, nonBcpInterface, sibling,366testSuperSiblingObj, testSubObj,367true, ClassCastException.class);368}369}370}371372/**373* Tests bootclasspath reference to reference conversions.374*/375public static void testBCPRef2BCPRef() {376Class bcpInterface = CharSequence.class;377Class bcpSubClass1 = String.class;378Class bcpSubClass2 = StringBuffer.class;379Object testObj01 = new String("test");380Object testObj02 = new StringBuffer("test");381Class[] children = {bcpSubClass1, bcpSubClass2};382Object[] childInst = {testObj01, testObj02};383for (TestConversionMode mode : TestConversionMode.values()) {384for (int i = 0; i < children.length; i++) {385// Child type to parent type non-null conversion, shoud succeed386testConversion(mode, children[i], bcpInterface, childInst[i],387childInst[i], false, null);388// Child type to parent type null conversion, shoud succeed389testConversion(mode, children[i], bcpInterface, null,390null, false, null);391// Parent type to child type non-null conversion with child392// type instance, should succeed393testConversion(mode, bcpInterface,394children[i], childInst[i], childInst[i], false, null);395// Parent type to child type null conversion, should succeed396testConversion(mode, bcpInterface,397children[i], null, null, false, null);398}399// Sibling type non-null conversion, should fail400testConversion(mode, bcpSubClass1,401bcpSubClass2, testObj01, null, true,402ClassCastException.class);403// Sibling type null conversion, should succeed404testConversion(mode, bcpSubClass1,405bcpSubClass2, null, null, false, null);406// Parent type to child type non-null conversion with sibling407// type instance, should fail408testConversion(mode, bcpInterface, bcpSubClass1, testObj02,409null, true, ClassCastException.class);410}411}412413/**414* Dummy method used in {@link #testReturnAny2Void} and415* {@link #testReturnVoid2Any} tests to form a method handle.416*/417public static void retVoid() {}418419/**420* Tests that non-null any return is successfully converted to non-type421* void.422*/423public static void testReturnAny2Void() {424for (Wrapper from : Wrapper.values()) {425testConversion(TestConversionMode.RETURN_VALUE, from.wrapperType(),426void.class, RANDOM_VALUES.get(from),427null, false, null);428testConversion(TestConversionMode.RETURN_VALUE, from.primitiveType(),429void.class, RANDOM_VALUES.get(from),430null, false, null);431}432}433434/**435* Tests that void return is successfully converted to primitive and436* reference. Result should be zero for primitives and null for references.437*/438public static void testReturnVoid2Any() {439for (Wrapper to : Wrapper.values()) {440testConversion(TestConversionMode.RETURN_VALUE, void.class,441to.primitiveType(), null,442to.zero(), false, null);443testConversion(TestConversionMode.RETURN_VALUE, void.class,444to.wrapperType(), null,445null, false, null);446}447}448449private static void checkForWrongMethodTypeException(MethodHandle mh, MethodType mt) {450try {451MethodHandles.explicitCastArguments(mh, mt);452throw new AssertionError("Expected WrongMethodTypeException is not thrown");453} catch (WrongMethodTypeException wmte) {454if (VERBOSE) {455System.out.printf("Expected exception %s: %s\n",456wmte.getClass(), wmte.getMessage());457}458}459}460461/**462* Tests that MHs.eCA method works correctly with MHs with multiple arguments.463* @throws Throwable464*/465public static void testMultipleArgs() throws Throwable {466int arity = 1 + RNG.nextInt(Helper.MAX_ARITY / 2 - 2);467int arityMinus = RNG.nextInt(arity);468int arityPlus = arity + RNG.nextInt(Helper.MAX_ARITY / 2 - arity) + 1;469MethodType mType = Helper.randomMethodTypeGenerator(arity);470MethodType mTypeNew = Helper.randomMethodTypeGenerator(arity);471MethodType mTypeNewMinus = Helper.randomMethodTypeGenerator(arityMinus);472MethodType mTypeNewPlus = Helper.randomMethodTypeGenerator(arityPlus);473Class<?> rType = mType.returnType();474MethodHandle original;475if (rType.equals(void.class)) {476MethodType mt = MethodType.methodType(void.class);477original = MethodHandles.publicLookup()478.findStatic(THIS_CLASS, "retVoid", mt);479} else {480Object rValue = Helper.castToWrapper(1, rType);481original = MethodHandles.constant(rType, rValue);482}483original = Helper.addTrailingArgs(original, arity, mType.parameterList());484MethodHandle target = MethodHandles485.explicitCastArguments(original, mTypeNew);486Object[] parList = Helper.randomArgs(mTypeNew.parameterList());487for (int i = 0; i < parList.length; i++) {488if (parList[i] instanceof String) {489parList[i] = null; //getting rid of Stings produced by randomArgs490}491}492target.invokeWithArguments(parList);493checkForWrongMethodTypeException(original, mTypeNewMinus);494checkForWrongMethodTypeException(original, mTypeNewPlus);495}496497/**498* Enumeration of test conversion modes.499*/500public enum TestConversionMode {501RETURN_VALUE,502ARGUMENT;503}504505/**506* Tests type and value conversion. Comparing with the given expected result.507*508* @param mode - test conversion mode. See {@link #TestConversionMode}.509* @param from - source type.510* @param to - destination type.511* @param param - value to be converted.512* @param expectedResult - expected value after conversion.513* @param failureExpected - true if conversion failure expected.514* @param expectedException - expected exception class if515* {@code failureExpected} is true.516*/517public static void testConversion(TestConversionMode mode,518Class<?> from, Class<?> to, Object param,519Object expectedResult, boolean failureExpected,520Class<? extends Throwable> expectedException) {521if (VERBOSE) {522System.out.printf("Testing return value conversion: "523+ "%-10s => %-10s: %5s: ", from.getSimpleName(),524to.getSimpleName(), param);525}526MethodHandle original = null;527MethodType newType = null;528switch (mode) {529case RETURN_VALUE:530if (from.equals(void.class)) {531MethodType mt = MethodType.methodType(void.class);532try {533original = MethodHandles.publicLookup()534.findStatic(THIS_CLASS, "retVoid", mt);535} catch (NoSuchMethodException | IllegalAccessException ex) {536throw new Error("Unexpected issue", ex);537}538} else {539original = MethodHandles.constant(from, param);540}541newType = original.type().changeReturnType(to);542break;543case ARGUMENT:544if (from.equals(void.class) || to.equals(void.class)) {545throw new Error("Test issue: argument conversion does not"546+ " work with non-type void");547}548original = MethodHandles.identity(to);549newType = original.type().changeParameterType(0, from);550break;551default:552String msg = String.format("Test issue: unknown test"553+ " convertion mode %s.", mode.name());554throw new Error(msg);555}556try {557MethodHandle target = MethodHandles558.explicitCastArguments(original, newType);559Object result;560switch (mode) {561case RETURN_VALUE:562result = target.invokeWithArguments();563break;564case ARGUMENT:565result = target.invokeWithArguments(param);566break;567default:568String msg = String.format("Test issue: unknown test"569+ " convertion mode %s.", mode.name());570throw new Error(msg);571}572if (!failureExpected573&& (expectedResult != null && !expectedResult.equals(result)574|| expectedResult == null && result != null)) {575String msg = String.format("Conversion result %s is not equal"576+ " to the expected result %10s",577result, expectedResult);578throw new AssertionError(msg);579}580if (VERBOSE) {581String resultStr;582if (result != null) {583resultStr = String.format("Converted value and type are"584+ " %10s (%10s)", "'" + result + "'",585result.getClass().getSimpleName());586} else {587resultStr = String.format("Converted value is %10s", result);588}589System.out.println(resultStr);590}591if (failureExpected) {592String msg = String.format("No exception thrown while testing"593+ " return value conversion: %10s => %10s;"594+ " parameter: %10s",595from, to, param);596throw new AssertionError(msg);597}598} catch (AssertionError e) {599throw e; // report test failure600} catch (Throwable e) {601if (VERBOSE) {602System.out.printf("%s: %s\n", e.getClass(), e.getMessage());603}604if (!failureExpected || !e.getClass().equals(expectedException)) {605String msg = String.format("Unexpected exception was thrown"606+ " while testing return value conversion:"607+ " %s => %s; parameter: %s", from, to, param);608throw new AssertionError(msg, e);609}610}611}612}613614615