/* * Copyright (c) 2021, 2023, 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. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 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. */ /* * @test * @bug 8271820 8300924 * @modules java.base/jdk.internal.reflect * @summary Test compliance of ConstructorAccessor, FieldAccessor, MethodAccessor implementations * @run testng/othervm --add-exports java.base/jdk.internal.reflect=ALL-UNNAMED -Djdk.reflect.useDirectMethodHandle=true -XX:-ShowCodeDetailsInExceptionMessages MethodHandleAccessorsTest */ /* * @test * @modules java.base/jdk.internal.reflect * @run testng/othervm --add-exports java.base/jdk.internal.reflect=ALL-UNNAMED -Djdk.reflect.useDirectMethodHandle=false -XX:-ShowCodeDetailsInExceptionMessages MethodHandleAccessorsTest */ import jdk.internal.reflect.ConstructorAccessor; import jdk.internal.reflect.FieldAccessor; import jdk.internal.reflect.MethodAccessor; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class MethodHandleAccessorsTest { static final boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle"); public static void public_static_V() {} public static int public_static_I() { return 42; } public void public_V() {} public int public_I() { return 42; } public static void public_static_I_V(int i) {} public static int public_static_I_I(int i) { return i; } public static void public_static_V_L3(Object o1, Object o2, Object o3) { } public static void public_static_V_L4(Object o1, Object o2, Object o3, Object o4) { } public static void public_V_L5(Object o1, Object o2, Object o3, Object o4, Object o5) { } public void public_I_V(int i) {} public int public_I_I(int i) { return i; } private static void private_static_V() {} private static int private_static_I() { return 42; } private void private_V() {} private int private_I() { return 42; } private static void private_static_I_V(int i) {} private static int private_static_I_I(int i) { return i; } private void private_I_V(int i) {} private int private_I_I(int i) { return i; } public static int varargs(int... values) { int sum = 0; for (int i : values) sum += i; return sum; } public static int varargs_primitive(int first, int... rest) { int sum = first; if (rest != null) { sum *= 100; for (int i : rest) sum += i; } return sum; } public static String varargs_object(String first, String... rest) { StringBuilder sb = new StringBuilder(first); if (rest != null) { sb.append(Stream.of(rest).collect(Collectors.joining(",", "[", "]"))); } return sb.toString(); } public static final class Public { public static final int STATIC_FINAL = 1; private final int i; private final String s; private static String name = "name"; private byte b = 9; public Public() { this.i = 0; this.s = null; } public Public(int i) { this.i = i; this.s = null; } public Public(String s) { this.i = 0; this.s = s; } public Public(byte b) { this.b = b; this.i = 0; this.s = null; } public Public(int first, int... rest) { this(varargs_primitive(first, rest)); } public Public(String first, String... rest) { this(varargs_object(first, rest)); } public Public(Object o1, Object o2, Object o3) { this("3-arg constructor"); } public Public(Object o1, Object o2, Object o3, Object o4) { this("4-arg constructor"); } public Public(RuntimeException exc) { throw exc; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Public other = (Public) o; return i == other.i && Objects.equals(s, other.s); } @Override public int hashCode() { return Objects.hash(i, s); } @Override public String toString() { return "Public{" + "i=" + i + ", s='" + s + '\'' + ", b=" + b + '}'; } } static final class Private { private final int i; private Private() { this.i = 0; } private Private(int i) { this.i = i; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Private other = (Private) o; return i == other.i; } @Override public int hashCode() { return Objects.hash(i); } @Override public String toString() { return "Private{" + "i=" + i + '}'; } } static final class Thrower { public Thrower(RuntimeException exc) { throw exc; } public static void throws_exception(RuntimeException exc) { throw exc; } } public static abstract class Abstract { public Abstract() { } } /** * Tests if MethodAccessor::invoke implementation returns the expected * result or exceptions. */ static void doTestAccessor(Method m, MethodAccessor ma, Object target, Object[] args, Object expectedReturn, Throwable... expectedExceptions) { Object ret; Throwable exc; try { ret = ma.invoke(target, args); exc = null; } catch (Throwable e) { ret = null; exc = e; } System.out.println("\n" + m + ", invoked with target: " + target + ", args: " + Arrays.toString(args)); chechResult(ret, expectedReturn, exc, expectedExceptions); } /** * Tests if ConstructorAccessor::newInstance implementation returns the * expected result or exceptions. */ static void doTestAccessor(Constructor c, ConstructorAccessor ca, Object[] args, Object expectedReturn, Throwable... expectedExceptions) { Object ret; Throwable exc; try { ret = ca.newInstance(args); exc = null; } catch (Throwable e) { ret = null; exc = e; } System.out.println("\n" + c + ", invoked with args: " + Arrays.toString(args)); chechResult(ret, expectedReturn, exc, expectedExceptions); } /** * Tests if FieldAccessor::get implementation returns the * expected result or exceptions. */ static void doTestAccessor(Field f, FieldAccessor fa, Object target, Object expectedValue, Throwable... expectedExceptions) { Object ret; Throwable exc; try { ret = fa.get(target); exc = null; } catch (Throwable e) { ret = null; exc = e; } System.out.println("\n" + f + ", invoked with target: " + target + ", value: " + ret); chechResult(ret, expectedValue, exc, expectedExceptions); } /** * Tests if FieldAccessor::set implementation returns the * expected result or exceptions. */ static void doTestAccessor(Field f, FieldAccessor fa, Object target, Object oldValue, Object newValue, Throwable... expectedExceptions) { Object ret; Throwable exc; try { fa.set(target, newValue); exc = null; ret = fa.get(target); } catch (Throwable e) { ret = null; exc = e; } System.out.println("\n" + f + ", invoked with target: " + target + ", value: " + ret); chechResult(ret, newValue, exc, expectedExceptions); } static void chechResult(Object ret, Object expectedReturn, Throwable exc, Throwable... expectedExceptions) { if (exc != null) { checkException(exc, expectedExceptions); } else if (expectedExceptions.length > 0) { fail(exc, expectedExceptions); } else if (!Objects.equals(ret, expectedReturn)) { throw new AssertionError("Expected return:\n " + expectedReturn + "\ngot:\n " + ret); } else { System.out.println(" Got expected return: " + ret); } } static void checkException(Throwable exc, Throwable... expectedExceptions) { boolean match = false; for (Throwable expected : expectedExceptions) { if (exceptionMatches(exc, expected)) { match = true; break; } } if (match) { System.out.println(" Got expected exception: " + exc); if (exc.getCause() != null) { System.out.println(" with cause: " + exc.getCause()); } } else { fail(exc, expectedExceptions); } } static boolean exceptionMatches(Throwable exc, Throwable expected) { return expected.getClass().isInstance(exc) && (Objects.equals(expected.getMessage(), exc.getMessage()) || (exc.getMessage() != null && expected.getMessage() != null && exc.getMessage().startsWith(expected.getMessage()))) && (expected.getCause() == null || exceptionMatches(exc.getCause(), expected.getCause())); } static void fail(Throwable thrownException, Throwable... expectedExceptions) { String msg; if (thrownException == null) { msg = "No exception thrown but there were expected exceptions (see suppressed)"; } else if (expectedExceptions.length == 0) { msg = "Exception thrown (see cause) but there were no expected exceptions"; } else { msg = "Exception thrown (see cause) but expected exceptions were different (see suppressed)"; } AssertionError error = new AssertionError(msg, thrownException); Stream.of(expectedExceptions).forEach(error::addSuppressed); throw error; } static void doTest(Method m, Object target, Object[] args, Object expectedReturn, Throwable... expectedException) { MethodAccessor ma = ReflectionFactory.getReflectionFactory().newMethodAccessor(m, Reflection.isCallerSensitive(m)); try { doTestAccessor(m, ma, target, args, expectedReturn, expectedException); } catch (Throwable e) { throw new RuntimeException(ma.getClass().getName() + " for method: " + m + " test failure", e); } } static void doTest(Constructor c, Object[] args, Object expectedReturn, Throwable... expectedExceptions) { ConstructorAccessor ca = ReflectionFactory.getReflectionFactory().newConstructorAccessor(c); try { doTestAccessor(c, ca, args, expectedReturn, expectedExceptions); } catch (Throwable e) { throw new RuntimeException(ca.getClass().getName() + " for constructor: " + c + " test failure", e); } } static void doTest(Field f, Object target, Object expectedValue, Throwable... expectedExceptions) { FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(f, false); try { doTestAccessor(f, fa, target, expectedValue, expectedExceptions); } catch (Throwable e) { throw new RuntimeException(fa.getClass().getName() + " for field: " + f + " test failure", e); } } static void doTest(Field f, Object target, Object oldValue, Object newValue, Throwable... expectedExceptions) { FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(f, true); try { doTestAccessor(f, fa, target, oldValue, newValue, expectedExceptions); } catch (Throwable e) { throw new RuntimeException(fa.getClass().getName() + " for field: " + f + " test failure", e); } } private static final Throwable[] noException = new Throwable[0]; private static final Throwable[] mismatched_argument_type = new Throwable[] { new IllegalArgumentException("argument type mismatch") }; private static final Throwable[] mismatched_target_type = new Throwable[] { new IllegalArgumentException("argument type mismatch"), new IllegalArgumentException("object is not an instance of declaring class"), }; private static final Throwable[] cannot_get_field = new Throwable[] { new IllegalArgumentException("Can not get") }; private static final Throwable[] cannot_set_field = new Throwable[] { new IllegalArgumentException("Can not set") }; private static final Throwable[] mismatched_field_type = new Throwable[] { new IllegalArgumentException("Can not set") }; private static final Throwable[] wrong_argument_count_no_details = new Throwable[] { new IllegalArgumentException("wrong number of arguments") }; private static final Throwable[] wrong_argument_count_zero_args = new Throwable[] { new IllegalArgumentException("wrong number of arguments: 0 expected:") }; private static final Throwable[] wrong_argument_count = new Throwable[] { new IllegalArgumentException("wrong number of arguments"), new IllegalArgumentException("array is not of length 1") }; private static final Throwable[] null_argument = new Throwable[] { new IllegalArgumentException("wrong number of arguments"), new IllegalArgumentException("null array reference") }; private static final Throwable[] null_argument_value = new Throwable[] { new IllegalArgumentException() }; private static final Throwable[] null_argument_value_npe = new Throwable[] { new IllegalArgumentException("java.lang.NullPointerException"), new NullPointerException() }; private static final Throwable[] null_target = new Throwable[] { new NullPointerException() }; private static final Throwable[] wrapped_npe_no_msg = new Throwable[]{ new InvocationTargetException(new NullPointerException()) }; private static final Throwable[] wrapped_npe = new Throwable[]{ new InvocationTargetException(new NullPointerException("NPE")) }; private static final Throwable[] wrapped_cce = new Throwable[]{ new InvocationTargetException(new ClassCastException("CCE")) }; private static final Throwable[] wrapped_iae = new Throwable[]{ new InvocationTargetException(new IllegalArgumentException("IAE")) }; @DataProvider(name = "testNoArgMethods") private Object[][] testNoArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Object[] emptyArgs = new Object[]{}; return new Object[][] { new Object[] {"public_static_V", null, emptyArgs, null, noException}, new Object[] {"public_static_V", null, null, null, noException}, new Object[] {"public_static_I", null, emptyArgs, 42, noException}, new Object[] {"public_static_I", null, null, 42, noException}, new Object[] {"public_V", inst, emptyArgs, null, noException}, new Object[] {"public_V", inst, null, null, noException}, new Object[] {"public_I", inst, emptyArgs, 42, noException}, new Object[] {"public_I", inst, null, 42, noException}, new Object[] {"private_static_V", null, emptyArgs, null, noException}, new Object[] {"private_static_I", null, emptyArgs, 42, noException}, new Object[] {"private_V", inst, emptyArgs, null, noException}, new Object[] {"private_I", inst, emptyArgs, 42, noException}, new Object[] {"public_V", null, null, null, null_target}, }; } @DataProvider(name = "testOneArgMethods") private Object[][] testOneArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Object wrongInst = new Object(); return new Object[][]{ new Object[] {"public_static_I_V", int.class, null, new Object[]{12}, null, noException}, new Object[] {"public_static_I_I", int.class, null, new Object[]{12}, 12, noException}, new Object[] {"public_I_V", int.class, inst, new Object[]{12}, null, noException}, new Object[] {"public_I_I", int.class, inst, new Object[]{12}, 12, noException}, new Object[] {"private_static_I_V", int.class, null, new Object[]{12}, null, noException}, new Object[] {"private_static_I_I", int.class, null, new Object[]{12}, 12, noException}, new Object[] {"private_I_V", int.class, inst, new Object[]{12}, null, noException}, new Object[] {"private_I_I", int.class, inst, new Object[]{12}, 12, noException}, new Object[] {"public_static_I_I", int.class, null, new Object[]{"a"}, null, mismatched_argument_type}, new Object[] {"public_I_I", int.class, inst, new Object[]{"a"}, null, mismatched_argument_type}, new Object[] {"public_static_I_I", int.class, null, new Object[]{12, 13}, null, newImpl ? wrong_argument_count_no_details : wrong_argument_count}, new Object[] {"public_I_I", int.class, inst, new Object[]{12, 13}, null, newImpl ? wrong_argument_count_no_details : wrong_argument_count}, new Object[] {"public_I_I", int.class, wrongInst, new Object[]{12}, 12, mismatched_target_type}, new Object[] {"public_I_I", int.class, null, new Object[]{12}, 12, null_target}, new Object[] {"public_static_I_V", int.class, null, null, null, newImpl ? wrong_argument_count_no_details : null_argument}, new Object[] {"public_static_I_V", int.class, null, new Object[]{null}, null, newImpl ? null_argument_value_npe : null_argument_value}, new Object[] {"public_I_I", int.class, inst, null, null, null_argument}, new Object[] {"public_I_I", int.class, inst, new Object[]{null}, null, newImpl ? null_argument_value_npe : null_argument_value}, }; } @DataProvider(name = "testMultiArgMethods") private Object[][] testMultiArgMethods() { MethodHandleAccessorsTest inst = new MethodHandleAccessorsTest(); Class[] params_L3 = new Class[] { Object.class, Object.class, Object.class}; Class[] params_L4 = new Class[] { Object.class, Object.class, Object.class, Object.class}; Class[] params_L5 = new Class[] { Object.class, Object.class, Object.class, Object.class, Object.class}; return new Object[][]{ new Object[]{"public_static_V_L3", params_L3, null, new Object[3], null, noException}, new Object[]{"public_static_V_L4", params_L4, null, new Object[4], null, noException}, new Object[]{"public_V_L5", params_L5, inst, new Object[5], null, noException}, // wrong arguments new Object[]{"public_static_V_L3", params_L3, null, null, null, newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details}, new Object[]{"public_static_V_L4", params_L4, null, new Object[0], null, newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details}, new Object[]{"public_V_L5", params_L5, inst, null, null, newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details}, }; } @DataProvider(name = "testMethodsWithVarargs") private Object[][] testMethodsWithVarargs() { Class[] paramTypes = new Class[] { int[].class }; Class[] I_paramTypes = new Class[] { int.class, int[].class }; Class[] L_paramTypes = new Class[] { String.class, String[].class }; return new Object[][]{ new Object[] {"varargs", paramTypes, null, new Object[]{new int[]{1, 2, 3}}, 6, noException}, new Object[] {"varargs", paramTypes, null, new Object[]{new int[]{}}, 0, noException}, new Object[] {"varargs", paramTypes, null, new Object[]{null}, 0, wrapped_npe_no_msg}, new Object[] {"varargs_primitive", I_paramTypes, null, new Object[]{1, new int[]{2, 3}}, 105, noException}, new Object[] {"varargs_primitive", I_paramTypes, null, new Object[]{1, new int[]{}}, 100, noException}, new Object[] {"varargs_primitive", I_paramTypes, null, new Object[]{1, null}, 1, noException}, new Object[] {"varargs_object", L_paramTypes, null, new Object[]{"a", new String[]{"b", "c"}}, "a[b,c]", noException}, new Object[] {"varargs_object", L_paramTypes, null, new Object[]{"a", new String[]{}}, "a[]", noException}, new Object[] {"varargs_object", L_paramTypes, null, new Object[]{"a", null}, "a", noException}, }; } @Test(dataProvider = "testNoArgMethods") public void testNoArgMethod(String methodname, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname), target, args, expectedReturn, expectedExpections); } @Test(dataProvider = "testOneArgMethods") public void testOneArgMethod(String methodname, Class paramType, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramType), target, args, expectedReturn, expectedExpections); } @Test(dataProvider = "testMultiArgMethods") public void testMultiArgMethod(String methodname, Class[] paramTypes, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramTypes), target, args, expectedReturn, expectedExpections); } @Test(dataProvider = "testMethodsWithVarargs") public void testMethodsWithVarargs(String methodname, Class[] paramTypes, Object target, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(MethodHandleAccessorsTest.class.getDeclaredMethod(methodname, paramTypes), target, args, expectedReturn, expectedExpections); } @DataProvider(name = "testConstructors") private Object[][] testConstructors() { return new Object[][]{ new Object[]{null, new Object[]{}, new Public(), noException}, new Object[]{null, null, new Public(), noException}, new Object[]{new Class[]{int.class}, new Object[]{12}, new Public(12), noException}, new Object[]{new Class[]{String.class}, new Object[]{"a"}, new Public("a"), noException}, new Object[]{new Class[]{int.class, int[].class}, new Object[]{1, new int[]{2, 3}}, new Public(105), noException}, new Object[]{new Class[]{int.class, int[].class}, new Object[]{1, new int[]{}}, new Public(100), noException}, new Object[]{new Class[]{int.class, int[].class}, new Object[]{1, null}, new Public(1), noException}, new Object[]{new Class[]{String.class, String[].class}, new Object[]{"a", new String[]{"b", "c"}}, new Public("a[b,c]"), noException}, new Object[]{new Class[]{String.class, String[].class}, new Object[]{"a", new String[]{}}, new Public("a[]"), noException}, new Object[]{new Class[]{String.class, String[].class}, new Object[]{"a", null}, new Public("a"), noException}, // test ConstructorAccessor exceptions thrown new Object[]{new Class[]{int.class}, new Object[]{"a"}, null, mismatched_argument_type}, new Object[]{new Class[]{int.class}, new Object[]{12, 13}, null, wrong_argument_count}, new Object[]{new Class[]{int.class}, null, null, null_argument}, new Object[]{new Class[]{RuntimeException.class}, new Object[]{new NullPointerException("NPE")}, null, wrapped_npe}, new Object[]{new Class[]{RuntimeException.class}, new Object[]{new IllegalArgumentException("IAE")}, null, wrapped_iae}, new Object[]{new Class[]{RuntimeException.class}, new Object[]{new ClassCastException("CCE")}, null, wrapped_cce}, }; } @Test(dataProvider = "testConstructors") public void testPublicConstructors(Class[] paramTypes, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections); } @DataProvider(name = "testMultiArgConstructors") private Object[][] testMultiArgConstructors() { Class[] params_L3 = new Class[] { Object.class, Object.class, Object.class}; Class[] params_L4 = new Class[] { Object.class, Object.class, Object.class, Object.class}; Object o = "arg"; return new Object[][]{ new Object[]{params_L3, new Object[3], new Public(o, o, o), noException}, new Object[]{params_L4, new Object[4], new Public(o, o, o, o), noException}, new Object[]{params_L3, new Object[]{}, null, newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details}, new Object[]{params_L4, null, null, newImpl ? wrong_argument_count_zero_args : wrong_argument_count_no_details}, }; } @Test(dataProvider = "testMultiArgConstructors") public void testMultiArgConstructors(Class[] paramTypes, Object[] args, Object expectedReturn, Throwable[] expectedExpections) throws Exception { doTest(Public.class.getDeclaredConstructor(paramTypes), args, expectedReturn, expectedExpections); } @Test public void testOtherConstructors() throws Exception { doTest(Private.class.getDeclaredConstructor(), new Object[]{}, new Private()); doTest(Private.class.getDeclaredConstructor(), null, new Private()); doTest(Private.class.getDeclaredConstructor(int.class), new Object[]{12}, new Private(12)); doTest(Abstract.class.getDeclaredConstructor(), null, null, new InstantiationException()); } @DataProvider(name = "throwException") private Object[][] throwException() { return new Object[][]{ new Object[] {new NullPointerException("NPE"), wrapped_npe}, new Object[] {new IllegalArgumentException("IAE"), wrapped_iae}, new Object[] {new ClassCastException("CCE"), wrapped_cce}, }; } /* * Test Method::invoke and Constructor::newInstance to wrap NPE/CCE/IAE * thrown by the member */ @Test(dataProvider = "throwException") public void testInvocationTargetException(Throwable ex, Throwable[] expectedExpections) throws Exception { Object[] args = new Object[] { ex }; // test static method doTest(Thrower.class.getDeclaredMethod("throws_exception", RuntimeException.class), null, args, null, expectedExpections); // test constructor doTest(Thrower.class.getDeclaredConstructor(RuntimeException.class), args, null, expectedExpections); } @Test public void testLambdaProxyClass() throws Exception { // test MethodAccessor on methods declared by hidden classes IntUnaryOperator intUnaryOp = i -> i; Method applyAsIntMethod = intUnaryOp.getClass().getDeclaredMethod("applyAsInt", int.class); doTest(applyAsIntMethod, intUnaryOp, new Object[]{12}, 12); } @DataProvider(name = "readAccess") private Object[][] readAccess() { boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle"); String wrongInst = new String(); return new Object[][]{ new Object[]{"i", new Public(100), 100, noException}, new Object[]{"s", new Public("test"), "test", noException}, new Object[]{"s", null, "test", null_target}, new Object[]{"s", wrongInst, "test", newImpl ? cannot_get_field : cannot_set_field}, new Object[]{"b", wrongInst, 0, newImpl ? cannot_get_field : cannot_set_field}, }; } @DataProvider(name = "writeAccess") private Object[][] writeAccess() { Object o = new Object(); byte b = 1; return new Object[][]{ new Object[]{"i", new Public(100), 100, 200, noException}, new Object[]{"i", new Public(100), 100, Integer.valueOf(10), noException}, new Object[]{"s", new Public("test"), "test", "newValue", noException}, new Object[]{"s", null, "test", "dummy", null_target}, new Object[]{"b", new Public(b), b, null, mismatched_field_type}, new Object[]{"b", new Public(b), b, Long.valueOf(10), mismatched_field_type}, new Object[]{"name", null, "name", o, mismatched_field_type}, new Object[]{"i", new Public(100), 100, o, mismatched_field_type}, }; } @Test(dataProvider = "readAccess") public void testFieldReadAccess(String name, Object target, Object expectedValue, Throwable[] expectedExpections) throws Exception { Field f = Public.class.getDeclaredField(name); f.setAccessible(true); doTest(f, target, expectedValue, expectedExpections); } @Test(dataProvider = "writeAccess") public void testFieldWriteAccess(String name, Object target, Object oldValue, Object newValue, Throwable[] expectedExpections) throws Exception { Field f = Public.class.getDeclaredField(name); f.setAccessible(true); doTest(f, target, oldValue, newValue, expectedExpections); } // test static final field with read-only access @Test public void testStaticFinalFields() throws Exception { Field f = Public.class.getDeclaredField("STATIC_FINAL"); doTest(f, new Public(), 1, noException); try { f.setInt(null, 100); } catch (IllegalAccessException e) { } } }