jdk-24/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java
Mandy Chung 5cea53d372 8315810: Reimplement sun.reflect.ReflectionFactory::newConstructorForSerialization with method handles
Co-authored-by: Chen Liang <liach@openjdk.org>
Reviewed-by: rriggs
2023-09-14 16:10:55 +00:00

701 lines
31 KiB
Java

/*
* 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 -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 {
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 of type java.lang.Object is not an instance of MethodHandleAccessorsTest"),
};
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, wrong_argument_count_no_details},
new Object[] {"public_I_I", int.class, inst, new Object[]{12, 13}, null, wrong_argument_count_no_details},
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, wrong_argument_count_no_details},
new Object[] {"public_static_I_V", int.class, null, new Object[]{null}, null, null_argument_value_npe},
new Object[] {"public_I_I", int.class, inst, null, null, null_argument},
new Object[] {"public_I_I", int.class, inst, new Object[]{null}, null, null_argument_value_npe},
};
}
@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, wrong_argument_count_zero_args},
new Object[]{"public_static_V_L4", params_L4, null, new Object[0], null, wrong_argument_count_zero_args},
new Object[]{"public_V_L5", params_L5, inst, null, null, wrong_argument_count_zero_args},
};
}
@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, wrong_argument_count_zero_args},
new Object[]{params_L4, null, null, wrong_argument_count_zero_args},
};
}
@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() {
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", cannot_get_field},
new Object[]{"b", wrongInst, 0, cannot_get_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) { }
}
}