/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.WrongMethodTypeException; import java.lang.reflect.Field; public class Main { public static class ValueHolder { public boolean m_z = false; public byte m_b = 0; public char m_c = 'a'; public short m_s = 0; public int m_i = 0; public float m_f = 0.0f; public double m_d = 0.0; public long m_j = 0; public String m_l = "a"; public static boolean s_z; public static byte s_b; public static char s_c; public static short s_s; public static int s_i; public static float s_f; public static double s_d; public static long s_j; public static String s_l; public final int m_fi = 0xa5a5a5a5; public static final int s_fi = 0x5a5a5a5a; private boolean m_pz; private static final boolean s_fz = false; } public static class Tester { public static void assertEquals(boolean expected, boolean actual) { if (actual != expected) { throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")"); } } public static void assertEquals(char expected, char actual) { if (actual != expected) { throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")"); } } public static void assertEquals(int expected, int actual) { if (actual != expected) { throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")"); } } public static void assertTrue(boolean value) throws AssertionError { if (!value) { throw new AssertionError("Value is not true"); } } public static void fail() throws Throwable{ throw new Error("fail"); } } public static class InvokeExactTester extends Tester { private enum PrimitiveType { Boolean, Byte, Char, Short, Int, Long, Float, Double, String, } private enum AccessorType { IPUT, SPUT, IGET, SGET, } static void setByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable { setByte(m, null, value, expectFailure); } static void getByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final byte got; if (v == null) { got = (byte) m.invokeExact(); } else { got = (byte) m.invokeExact(v); } assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable { getByte(m, null, value, expectFailure); } static void setChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setChar(MethodHandle m, char value, boolean expectFailure) throws Throwable { setChar(m, null, value, expectFailure); } static void getChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final char got; if (v == null) { got = (char) m.invokeExact(); } else { got = (char) m.invokeExact(v); } assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getChar(MethodHandle m, char value, boolean expectFailure) throws Throwable { getChar(m, null, value, expectFailure); } static void setShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setShort(MethodHandle m, short value, boolean expectFailure) throws Throwable { setShort(m, null, value, expectFailure); } static void getShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final short got = (v == null) ? (short) m.invokeExact() : (short) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getShort(MethodHandle m, short value, boolean expectFailure) throws Throwable { getShort(m, null, value, expectFailure); } static void setInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setInt(MethodHandle m, int value, boolean expectFailure) throws Throwable { setInt(m, null, value, expectFailure); } static void getInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final int got = (v == null) ? (int) m.invokeExact() : (int) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getInt(MethodHandle m, int value, boolean expectFailure) throws Throwable { getInt(m, null, value, expectFailure); } static void setLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setLong(MethodHandle m, long value, boolean expectFailure) throws Throwable { setLong(m, null, value, expectFailure); } static void getLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final long got = (v == null) ? (long) m.invokeExact() : (long) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getLong(MethodHandle m, long value, boolean expectFailure) throws Throwable { getLong(m, null, value, expectFailure); } static void setFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable { setFloat(m, null, value, expectFailure); } static void getFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final float got = (v == null) ? (float) m.invokeExact() : (float) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable { getFloat(m, null, value, expectFailure); } static void setDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setDouble(MethodHandle m, double value, boolean expectFailure) throws Throwable { setDouble(m, null, value, expectFailure); } static void getDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final double got = (v == null) ? (double) m.invokeExact() : (double) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getDouble(MethodHandle m, double value, boolean expectFailure) throws Throwable { getDouble(m, null, value, expectFailure); } static void setString(MethodHandle m, ValueHolder v, String value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setString(MethodHandle m, String value, boolean expectFailure) throws Throwable { setString(m, null, value, expectFailure); } static void getString(MethodHandle m, ValueHolder v, String value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final String got = (v == null) ? (String) m.invokeExact() : (String) m.invokeExact(v); assertTrue(got.equals(value)); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getString(MethodHandle m, String value, boolean expectFailure) throws Throwable { getString(m, null, value, expectFailure); } static void setBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { if (v == null) { m.invokeExact(value); } else { m.invokeExact(v, value); } } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void setBoolean(MethodHandle m, boolean value, boolean expectFailure) throws Throwable { setBoolean(m, null, value, expectFailure); } static void getBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure) throws Throwable { boolean exceptionThrown = false; try { final boolean got = (v == null) ? (boolean) m.invokeExact() : (boolean) m.invokeExact(v); assertTrue(got == value); } catch (WrongMethodTypeException e) { exceptionThrown = true; } assertEquals(expectFailure, exceptionThrown); } static void getBoolean(MethodHandle m, boolean value, boolean expectFailure) throws Throwable { getBoolean(m, null, value, expectFailure); } static boolean resultFor(PrimitiveType actualType, PrimitiveType expectedType, AccessorType actualAccessor, AccessorType expectedAccessor) { return (actualType != expectedType) || (actualAccessor != expectedAccessor); } static void tryAccessor(MethodHandle methodHandle, ValueHolder valueHolder, PrimitiveType primitive, Object value, AccessorType accessor) throws Throwable { boolean booleanValue = value instanceof Boolean ? ((Boolean) value).booleanValue() : false; setBoolean(methodHandle, valueHolder, booleanValue, resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IPUT)); setBoolean(methodHandle, booleanValue, resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SPUT)); getBoolean(methodHandle, valueHolder, booleanValue, resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IGET)); getBoolean(methodHandle, booleanValue, resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SGET)); byte byteValue = value instanceof Byte ? ((Byte) value).byteValue() : (byte) 0; setByte(methodHandle, valueHolder, byteValue, resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IPUT)); setByte(methodHandle, byteValue, resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SPUT)); getByte(methodHandle, valueHolder, byteValue, resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IGET)); getByte(methodHandle, byteValue, resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SGET)); char charValue = value instanceof Character ? ((Character) value).charValue() : 'z'; setChar(methodHandle, valueHolder, charValue, resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IPUT)); setChar(methodHandle, charValue, resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SPUT)); getChar(methodHandle, valueHolder, charValue, resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IGET)); getChar(methodHandle, charValue, resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SGET)); short shortValue = value instanceof Short ? ((Short) value).shortValue() : (short) 0; setShort(methodHandle, valueHolder, shortValue, resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IPUT)); setShort(methodHandle, shortValue, resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SPUT)); getShort(methodHandle, valueHolder, shortValue, resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IGET)); getShort(methodHandle, shortValue, resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SGET)); int intValue = value instanceof Integer ? ((Integer) value).intValue() : -1; setInt(methodHandle, valueHolder, intValue, resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IPUT)); setInt(methodHandle, intValue, resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SPUT)); getInt(methodHandle, valueHolder, intValue, resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IGET)); getInt(methodHandle, intValue, resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SGET)); long longValue = value instanceof Long ? ((Long) value).longValue() : (long) -1; setLong(methodHandle, valueHolder, longValue, resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IPUT)); setLong(methodHandle, longValue, resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SPUT)); getLong(methodHandle, valueHolder, longValue, resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IGET)); getLong(methodHandle, longValue, resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SGET)); float floatValue = value instanceof Float ? ((Float) value).floatValue() : -1.0f; setFloat(methodHandle, valueHolder, floatValue, resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IPUT)); setFloat(methodHandle, floatValue, resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SPUT)); getFloat(methodHandle, valueHolder, floatValue, resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IGET)); getFloat(methodHandle, floatValue, resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SGET)); double doubleValue = value instanceof Double ? ((Double) value).doubleValue() : -1.0; setDouble(methodHandle, valueHolder, doubleValue, resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IPUT)); setDouble(methodHandle, doubleValue, resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SPUT)); getDouble(methodHandle, valueHolder, doubleValue, resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IGET)); getDouble(methodHandle, doubleValue, resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SGET)); String stringValue = value instanceof String ? ((String) value) : "No Spock, no"; setString(methodHandle, valueHolder, stringValue, resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IPUT)); setString(methodHandle, stringValue, resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SPUT)); getString(methodHandle, valueHolder, stringValue, resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IGET)); getString(methodHandle, stringValue, resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SGET)); } public static void main() throws Throwable { ValueHolder valueHolder = new ValueHolder(); MethodHandles.Lookup lookup = MethodHandles.lookup(); boolean [] booleans = { false, true, false }; for (boolean b : booleans) { Boolean boxed = new Boolean(b); tryAccessor(lookup.findSetter(ValueHolder.class, "m_z", boolean.class), valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_z", boolean.class), valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET); assertTrue(valueHolder.m_z == b); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class), valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class), valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_z == b); } byte [] bytes = { (byte) 0x73, (byte) 0xfe }; for (byte b : bytes) { Byte boxed = new Byte(b); tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class), valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_b", byte.class), valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET); assertTrue(valueHolder.m_b == b); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_b", byte.class), valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_b", byte.class), valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_b == b); } char [] chars = { 'a', 'b', 'c' }; for (char c : chars) { Character boxed = new Character(c); tryAccessor(lookup.findSetter(ValueHolder.class, "m_c", char.class), valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_c", char.class), valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET); assertTrue(valueHolder.m_c == c); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_c", char.class), valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_c", char.class), valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_c == c); } short [] shorts = { (short) 0x1234, (short) 0x4321 }; for (short s : shorts) { Short boxed = new Short(s); tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class), valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_s", short.class), valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET); assertTrue(valueHolder.m_s == s); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_s", short.class), valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_s", short.class), valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_s == s); } int [] ints = { -100000000, 10000000 }; for (int i : ints) { Integer boxed = new Integer(i); tryAccessor(lookup.findSetter(ValueHolder.class, "m_i", int.class), valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_i", int.class), valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET); assertTrue(valueHolder.m_i == i); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_i", int.class), valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_i", int.class), valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_i == i); } float [] floats = { 0.99f, -1.23e-17f }; for (float f : floats) { Float boxed = Float.valueOf(f); tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class), valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class), valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET); assertTrue(valueHolder.m_f == f); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_f", float.class), valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_f", float.class), valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_f == f); } double [] doubles = { 0.44444444444e37, -0.555555555e-37 }; for (double d : doubles) { Double boxed = Double.valueOf(d); tryAccessor(lookup.findSetter(ValueHolder.class, "m_d", double.class), valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class), valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET); assertTrue(valueHolder.m_d == d); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_d", double.class), valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_d", double.class), valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_d == d); } long [] longs = { 0x0123456789abcdefl, 0xfedcba9876543210l }; for (long j : longs) { Long boxed = new Long(j); tryAccessor(lookup.findSetter(ValueHolder.class, "m_j", long.class), valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_j", long.class), valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET); assertTrue(valueHolder.m_j == j); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_j", long.class), valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_j", long.class), valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET); assertTrue(ValueHolder.s_j == j); } String [] strings = { "octopus", "crab" }; for (String s : strings) { tryAccessor(lookup.findSetter(ValueHolder.class, "m_l", String.class), valueHolder, PrimitiveType.String, s, AccessorType.IPUT); tryAccessor(lookup.findGetter(ValueHolder.class, "m_l", String.class), valueHolder, PrimitiveType.String, s, AccessorType.IGET); assertTrue(s.equals(valueHolder.m_l)); tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_l", String.class), valueHolder, PrimitiveType.String, s, AccessorType.SPUT); tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_l", String.class), valueHolder, PrimitiveType.String, s, AccessorType.SGET); assertTrue(s.equals(ValueHolder.s_l)); } System.out.println("Passed MethodHandle.invokeExact() tests for accessors."); } } public static class FindAccessorTester extends Tester { public static void main() throws Throwable { // NB having a static field test here is essential for // this test. MethodHandles need to ensure the class // (ValueHolder) is initialized. This happens in the // invoke-polymorphic dispatch. MethodHandles.Lookup lookup = MethodHandles.lookup(); { MethodHandle mh = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class); int initialValue = (int) mh.invokeExact(); System.out.println(initialValue); } { MethodHandle mh = lookup.findStaticSetter(ValueHolder.class, "s_i", int.class); mh.invokeExact(0); } try { lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class); fail(); } catch (NoSuchFieldException expected) {} try { lookup.findGetter(ValueHolder.class, "s_fi", byte.class); fail(); } catch (NoSuchFieldException eexpected) {} try { lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class); fail(); } catch (IllegalAccessException expected) {} lookup.findGetter(ValueHolder.class, "m_fi", int.class); try { lookup.findGetter(ValueHolder.class, "m_fi", byte.class); fail(); } catch (NoSuchFieldException expected) {} try { lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class); fail(); } catch (NoSuchFieldException expected) {} try { lookup.findSetter(ValueHolder.class, "m_fi", int.class); fail(); } catch (IllegalAccessException expected) {} System.out.println("Passed MethodHandles.Lookup tests for accessors."); } } public static class InvokeTester extends Tester { private static void testStaticGetter() throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle h0 = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class); h0.invoke(); Number t = (Number) h0.invoke(); int u = (int) h0.invoke(); Integer v = (Integer) h0.invoke(); long w = (long) h0.invoke(); try { byte x = (byte) h0.invoke(); fail(); } catch (WrongMethodTypeException expected) {} try { String y = (String) h0.invoke(); fail(); } catch (WrongMethodTypeException expected) {} try { Long z = (Long) h0.invoke(); fail(); } catch (WrongMethodTypeException expected) {} } private static void testMemberGetter() throws Throwable { ValueHolder valueHolder = new ValueHolder(); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle h0 = lookup.findGetter(ValueHolder.class, "m_fi", int.class); h0.invoke(valueHolder); Number t = (Number) h0.invoke(valueHolder); int u = (int) h0.invoke(valueHolder); Integer v = (Integer) h0.invoke(valueHolder); long w = (long) h0.invoke(valueHolder); try { byte x = (byte) h0.invoke(valueHolder); fail(); } catch (WrongMethodTypeException expected) {} try { String y = (String) h0.invoke(valueHolder); fail(); } catch (WrongMethodTypeException expected) {} try { Long z = (Long) h0.invoke(valueHolder); fail(); } catch (WrongMethodTypeException expected) {} } /*package*/ static Number getDoubleAsNumber() { return Double.valueOf(1.4e77); } /*package*/ static Number getFloatAsNumber() { return Float.valueOf(7.77f); } /*package*/ static Object getFloatAsObject() { return Float.valueOf(-7.77f); } private static void testMemberSetter() throws Throwable { ValueHolder valueHolder = new ValueHolder(); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class); MethodHandle s0 = lookup.findSetter(ValueHolder.class, "m_s", short.class); h0.invoke(valueHolder, 0.22f); h0.invoke(valueHolder, Float.valueOf(1.11f)); Number floatNumber = getFloatAsNumber(); h0.invoke(valueHolder, floatNumber); assertTrue(valueHolder.m_f == floatNumber.floatValue()); Object objNumber = getFloatAsObject(); h0.invoke(valueHolder, objNumber); assertTrue(valueHolder.m_f == ((Float) objNumber).floatValue()); try { h0.invoke(valueHolder, (Float) null); fail(); } catch (NullPointerException expected) {} // Test that type conversion checks work on small field types. short temp = (short) s0.invoke(valueHolder, new Byte((byte) 45)); assertTrue(temp == 0); assertTrue(valueHolder.m_s == 45); h0.invoke(valueHolder, (byte) 1); h0.invoke(valueHolder, (short) 2); h0.invoke(valueHolder, 3); h0.invoke(valueHolder, 4l); assertTrue(null == (Object) h0.invoke(valueHolder, 33)); assertTrue(0.0f == (float) h0.invoke(valueHolder, 33)); assertTrue(0l == (long) h0.invoke(valueHolder, 33)); try { h0.invoke(valueHolder, 0.33); fail(); } catch (WrongMethodTypeException expected) {} try { Number doubleNumber = getDoubleAsNumber(); h0.invoke(valueHolder, doubleNumber); fail(); } catch (ClassCastException expected) {} try { Number doubleNumber = null; h0.invoke(valueHolder, doubleNumber); fail(); } catch (NullPointerException expected) {} { // Mismatched return type - float != void float tmp = (float) h0.invoke(valueHolder, 0.45f); assertTrue(tmp == 0.0); } try { h0.invoke(valueHolder, "bam"); fail(); } catch (WrongMethodTypeException expected) {} try { String s = null; h0.invoke(valueHolder, s); fail(); } catch (WrongMethodTypeException expected) {} } private static void testStaticSetter() throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle s0 = lookup.findStaticSetter(ValueHolder.class, "s_s", short.class); MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class); h0.invoke(0.22f); h0.invoke(Float.valueOf(1.11f)); Number floatNumber = Float.valueOf(0.88f); h0.invoke(floatNumber); assertTrue(ValueHolder.s_f == floatNumber.floatValue()); try { h0.invoke((Float) null); fail(); } catch (NullPointerException expected) {} // Test that type conversion checks work on small field types. short temp = (short) s0.invoke(new Byte((byte) 45)); assertTrue(temp == 0); assertTrue(ValueHolder.s_s == 45); h0.invoke((byte) 1); h0.invoke((short) 2); h0.invoke(3); h0.invoke(4l); assertTrue(null == (Object) h0.invoke(33)); assertTrue(0.0f == (float) h0.invoke(33)); assertTrue(0l == (long) h0.invoke(33)); try { h0.invoke(0.33); fail(); } catch (WrongMethodTypeException expected) {} try { h0.invoke(Double.valueOf(0.33)); fail(); } catch (WrongMethodTypeException expected) {} try { Number doubleNumber = getDoubleAsNumber(); h0.invoke(doubleNumber); fail(); } catch (ClassCastException expected) {} try { Number doubleNumber = Double.valueOf(1.01); doubleNumber = (doubleNumber.doubleValue() != 0.1) ? null : doubleNumber; h0.invoke(doubleNumber); fail(); } catch (NullPointerException expected) {} try { // Mismatched return type - float != void float tmp = (float) h0.invoke(0.45f); assertTrue(tmp == 0.0); } catch (Exception e) { fail(); } try { h0.invoke("bam"); fail(); } catch (WrongMethodTypeException expected) {} try { String s = null; h0.invoke(s); fail(); } catch (WrongMethodTypeException expected) {} } public static void main() throws Throwable{ testStaticGetter(); testMemberGetter(); testStaticSetter(); testMemberSetter(); System.out.println("Passed MethodHandle.invoke() tests for accessors."); } } public static class UnreflectTester extends Tester { public static void main() throws Throwable { ValueHolder v = new ValueHolder(); { // public field test Field f = ValueHolder.class.getDeclaredField("m_c"); MethodHandles.lookup().unreflectSetter(f).invokeExact(v, 'z'); assertEquals('z', (char) MethodHandles.lookup().unreflectGetter(f).invokeExact(v)); MethodHandles.lookup().unreflectSetter(f).invokeExact(v, 'A'); assertEquals('A', (char) MethodHandles.lookup().unreflectGetter(f).invokeExact(v)); } { // public static final field test Field f = ValueHolder.class.getDeclaredField("s_fi"); try { MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} MethodHandles.lookup().unreflectGetter(f); f.setAccessible(true); int savedValue = (int) MethodHandles.lookup().unreflectGetter(f).invokeExact(); int newValue = savedValue + 1; MethodHandles.lookup().unreflectSetter(f).invokeExact(newValue); assertEquals(newValue, (int) MethodHandles.lookup().unreflectGetter(f).invokeExact() ); MethodHandles.lookup().unreflectSetter(f).invokeExact(savedValue); assertEquals(savedValue, (int) MethodHandles.lookup().unreflectGetter(f).invokeExact() ); f.setAccessible(false); try { MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} MethodHandles.lookup().unreflectGetter(f); } { // private field test Field f = ValueHolder.class.getDeclaredField("m_pz"); try { MethodHandle mh = MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} try { MethodHandle mh = MethodHandles.lookup().unreflectGetter(f); fail(); } catch (IllegalAccessException expected) {} f.setAccessible(true); MethodHandles.lookup().unreflectSetter(f).invokeExact(v, true); assertEquals(true, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact(v) ); MethodHandles.lookup().unreflectSetter(f).invokeExact(v, false); assertEquals(false, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact(v) ); f.setAccessible(false); try { MethodHandle mh = MethodHandles.lookup().unreflectGetter(f); fail(); } catch (IllegalAccessException expected) {} try { MethodHandle mh = MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} } { // private static final field test Field f = ValueHolder.class.getDeclaredField("s_fz"); // private static final field try { MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} try { MethodHandles.lookup().unreflectGetter(f); fail(); } catch (IllegalAccessException expected) {} f.setAccessible(true); // Setter is okay despite being final because field isAccessible(). MethodHandles.lookup().unreflectSetter(f).invokeExact(false); assertEquals(false, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact() ); MethodHandles.lookup().unreflectSetter(f).invokeExact(true); assertEquals(true, (boolean) MethodHandles.lookup().unreflectGetter(f).invokeExact() ); f.setAccessible(false); try { MethodHandles.lookup().unreflectSetter(f); fail(); } catch (IllegalAccessException expected) {} try { MethodHandles.lookup().unreflectGetter(f); fail(); } catch (IllegalAccessException expected) {} } System.out.println("Passed MethodHandles.unreflect(Field) tests."); } } public static void main(String[] args) throws Throwable { // FindAccessor test should be the first test class in this // file to ensure class initialization test is run. FindAccessorTester.main(); InvokeExactTester.main(); InvokeTester.main(); UnreflectTester.main(); } }