jdk-24/test/jdk/java/lang/reflect/Field/NegativeTest.java
Mandy Chung 9bfe415f66 8305104: Remove the old core reflection implementation
Reviewed-by: dholmes, alanb
2023-06-13 19:41:38 +00:00

582 lines
26 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 8277451
* @run testng NegativeTest
* @summary Test exception thrown due to bad receiver and bad value on
* Field with and without setAccessible(true)
*/
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class NegativeTest {
static class Fields {
public static int si;
public static char sc;
public static byte sb;
public static short ss;
public static long sl;
public static double sd;
public static float sf;
public static boolean sz;
public static String so;
public static final int sfi = 10;
public static final char sfc = 'a';
public static final byte sfb = 1;
public static final short sfs = 2;
public static final long sfl = 1000L;
public static final double sfd = 1.0;
public static final float sff = 2.0f;
public static final boolean sfz = true;
public static final String sfo = "abc";
public int i;
public char c;
public byte b;
public short s;
public long l;
public double d;
public float f;
public boolean z;
public String o;
public final int fi = 10;
public final char fc = 'a';
public final byte fb = 1;
public final short fs = 2;
public final long fl = 1000L;
public final double fd = 1.0;
public final float ff = 2.0f;
public final boolean fz = true;
public final String fo = "abc";
}
static final Field i_field = field("i", false);
static final Field c_field = field("c", false);
static final Field b_field = field("b", false);
static final Field s_field = field("s", false);
static final Field l_field = field("l", false);
static final Field d_field = field("d", false);
static final Field f_field = field("f", false);
static final Field z_field = field("z", false);
static final Field o_field = field("o", false);
static final Field fi_field = field("fi", false);
static final Field fc_field = field("fc", false);
static final Field fb_field = field("fb", false);
static final Field fs_field = field("fs", false);
static final Field fl_field = field("fl", false);
static final Field fd_field = field("fd", false);
static final Field ff_field = field("ff", false);
static final Field fz_field = field("fz", false);
static final Field fo_field = field("fo", false);
static final Field override_i_field = field("i", true);
static final Field override_c_field = field("c", true);
static final Field override_b_field = field("b", true);
static final Field override_s_field = field("s", true);
static final Field override_l_field = field("l", true);
static final Field override_d_field = field("d", true);
static final Field override_f_field = field("f", true);
static final Field override_z_field = field("z", true);
static final Field override_o_field = field("o", true);
static final Field override_fi_field = field("fi", true);
static final Field override_fc_field = field("fc", true);
static final Field override_fb_field = field("fb", true);
static final Field override_fs_field = field("fs", true);
static final Field override_fl_field = field("fl", true);
static final Field override_fd_field = field("fd", true);
static final Field override_ff_field = field("ff", true);
static final Field override_fz_field = field("fz", true);
static final Field override_fo_field = field("fo", true);
static final Field si_field = field("si", false);
static final Field sc_field = field("sc", false);
static final Field sb_field = field("sb", false);
static final Field ss_field = field("ss", false);
static final Field sl_field = field("sl", false);
static final Field sd_field = field("sd", false);
static final Field sf_field = field("sf", false);
static final Field sz_field = field("sz", false);
static final Field so_field = field("so", false);
static final Field sfi_field = field("sfi", false);
static final Field sfc_field = field("sfc", false);
static final Field sfb_field = field("sfb", false);
static final Field sfs_field = field("sfs", false);
static final Field sfl_field = field("sfl", false);
static final Field sfd_field = field("sfd", false);
static final Field sff_field = field("sff", false);
static final Field sfz_field = field("sfz", false);
static final Field sfo_field = field("sfo", false);
static final Field override_si_field = field("si", true);
static final Field override_sc_field = field("sc", true);
static final Field override_sb_field = field("sb", true);
static final Field override_ss_field = field("ss", true);
static final Field override_sl_field = field("sl", true);
static final Field override_sd_field = field("sd", true);
static final Field override_sf_field = field("sf", true);
static final Field override_sz_field = field("sz", true);
static final Field override_so_field = field("so", true);
static final Field override_sfi_field = field("sfi", true);
static final Field override_sfc_field = field("sfc", true);
static final Field override_sfb_field = field("sfb", true);
static final Field override_sfs_field = field("sfs", true);
static final Field override_sfl_field = field("sfl", true);
static final Field override_sfd_field = field("sfd", true);
static final Field override_sff_field = field("sff", true);
static final Field override_sfz_field = field("sfz", true);
static final Field override_sfo_field = field("sfo", true);
private static Field field(String name, boolean suppressAccessCheck) {
try {
Field f = Fields.class.getDeclaredField(name);
if (suppressAccessCheck) {
f.setAccessible(true);
}
return f;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
@DataProvider(name = "instanceFields")
private Object[][] instanceFields() {
return new Object[][]{
new Object[]{i_field},
new Object[]{c_field},
new Object[]{b_field},
new Object[]{s_field},
new Object[]{l_field},
new Object[]{d_field},
new Object[]{f_field},
new Object[]{z_field},
new Object[]{o_field},
new Object[]{override_i_field},
new Object[]{override_c_field},
new Object[]{override_b_field},
new Object[]{override_s_field},
new Object[]{override_l_field},
new Object[]{override_d_field},
new Object[]{override_f_field},
new Object[]{override_z_field},
new Object[]{override_o_field},
// final instance fields
new Object[]{fi_field},
new Object[]{fc_field},
new Object[]{fb_field},
new Object[]{fs_field},
new Object[]{fl_field},
new Object[]{fd_field},
new Object[]{ff_field},
new Object[]{fz_field},
new Object[]{fo_field},
new Object[]{override_fi_field},
new Object[]{override_fc_field},
new Object[]{override_fb_field},
new Object[]{override_fs_field},
new Object[]{override_fl_field},
new Object[]{override_fd_field},
new Object[]{override_ff_field},
new Object[]{override_fz_field},
new Object[]{override_fo_field},
};
}
private static Fields INSTANCE = new Fields();
/*
* Test Field::get on a good receiver, a bad receiver and null.
*
* IllegalArgumentException is thrown if the receiver is of
* a bad type. NullPointerException is thrown if the receiver is null.
*/
@Test(dataProvider = "instanceFields")
public void testReceiver(Field f) throws ReflectiveOperationException {
f.get(INSTANCE); // good receiver
testBadReceiver(f);
testNullReceiver(f);
}
/*
* IllegalArgumentException should be thrown for bad receiver type
*/
private void testBadReceiver(Field f) throws ReflectiveOperationException {
assertFalse(Modifier.isStatic(f.getModifiers())); // instance field
Object badObj = new NegativeTest();
try {
f.get(badObj);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
Class<?> fType = f.getType();
if (fType.isPrimitive()) {
try {
switch (fType.descriptorString()) {
case "B" -> f.getByte(badObj);
case "C" -> f.getChar(badObj);
case "D" -> f.getDouble(badObj);
case "F" -> f.getFloat(badObj);
case "I" -> f.getInt(badObj);
case "J" -> f.getLong(badObj);
case "S" -> f.getShort(badObj);
case "Z" -> f.getBoolean(badObj);
}
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
}
/*
* NullPointerException should be thrown for null receiver
*/
private void testNullReceiver(Field f) throws ReflectiveOperationException {
assertFalse(Modifier.isStatic(f.getModifiers())); // instance field
try {
f.get(null);
fail("expected NullPointerException");
} catch (NullPointerException e) {
// expected
}
Class<?> fType = f.getType();
if (fType.isPrimitive()) {
try {
switch (fType.descriptorString()) {
case "B" -> f.getByte(null);
case "C" -> f.getChar(null);
case "D" -> f.getDouble(null);
case "F" -> f.getFloat(null);
case "I" -> f.getInt(null);
case "J" -> f.getLong(null);
case "S" -> f.getShort(null);
case "Z" -> f.getBoolean(null);
}
fail("expected NullPointerException");
} catch (NullPointerException e) {
// expected
}
}
}
@DataProvider(name = "writeableFields")
private Object[][] writeableFields() {
Fields obj = new Fields();
return new Object[][]{
// instance fields with and without setAccessible(true)
new Object[]{i_field, obj, Integer.valueOf(10)},
new Object[]{c_field, obj, Character.valueOf('c')},
new Object[]{b_field, obj, Byte.valueOf((byte)1)},
new Object[]{s_field, obj, Short.valueOf((short)2)},
new Object[]{l_field, obj, Long.valueOf(1000)},
new Object[]{d_field, obj, Double.valueOf(1.2)},
new Object[]{f_field, obj, Float.valueOf(2.5f)},
new Object[]{z_field, obj, Boolean.valueOf(true)},
new Object[]{o_field, obj, "good-value"},
new Object[]{override_i_field, obj, Integer.valueOf(10)},
new Object[]{override_c_field, obj, Character.valueOf('c')},
new Object[]{override_b_field, obj, Byte.valueOf((byte)1)},
new Object[]{override_s_field, obj, Short.valueOf((short)2)},
new Object[]{override_l_field, obj, Long.valueOf(1000)},
new Object[]{override_d_field, obj, Double.valueOf(1.2)},
new Object[]{override_f_field, obj, Float.valueOf(2.5f)},
new Object[]{override_z_field, obj, Boolean.valueOf(true)},
new Object[]{override_o_field, obj, "good-value"},
// instance final fields with setAccessible(true)
new Object[]{override_fi_field, obj, Integer.valueOf(10)},
new Object[]{override_fc_field, obj, Character.valueOf('c')},
new Object[]{override_fb_field, obj, Byte.valueOf((byte)1)},
new Object[]{override_fs_field, obj, Short.valueOf((short)2)},
new Object[]{override_fl_field, obj, Long.valueOf(1000)},
new Object[]{override_fd_field, obj, Double.valueOf(1.2)},
new Object[]{override_ff_field, obj, Float.valueOf(2.5f)},
new Object[]{override_fz_field, obj, Boolean.valueOf(true)},
new Object[]{override_fo_field, obj, "good-value"},
// static fields with and without setAccessible(true)
new Object[]{si_field, null, Integer.valueOf(10)},
new Object[]{sc_field, null, Character.valueOf('c')},
new Object[]{sb_field, null, Byte.valueOf((byte)1)},
new Object[]{ss_field, null, Short.valueOf((short)2)},
new Object[]{sl_field, null, Long.valueOf(1000)},
new Object[]{sd_field, null, Double.valueOf(1.2)},
new Object[]{sf_field, null, Float.valueOf(2.5f)},
new Object[]{sz_field, null, Boolean.valueOf(true)},
new Object[]{so_field, null, "good-value"},
new Object[]{override_si_field, null, Integer.valueOf(10)},
new Object[]{override_sc_field, null, Character.valueOf('c')},
new Object[]{override_sb_field, null, Byte.valueOf((byte)1)},
new Object[]{override_ss_field, null, Short.valueOf((short)2)},
new Object[]{override_sl_field, null, Long.valueOf(1000)},
new Object[]{override_sd_field, null, Double.valueOf(1.2)},
new Object[]{override_sf_field, null, Float.valueOf(2.5f)},
new Object[]{override_sz_field, null, Boolean.valueOf(true)},
new Object[]{override_so_field, null, "good-value"},
};
}
/*
* Test Field::set with a good and bad value.
* Test setting to null if the field type is primitive.
*
* IllegalArgumentException is thrown if the value is of a bad type or null.
* NullPointerException is thrown if the receiver of an instance field is null.
* The receiver is checked
*/
@Test(dataProvider = "writeableFields")
public void testSetValue(Field f, Object obj, Object value) throws IllegalAccessException {
f.set(obj, value);
Class<?> fType = f.getType();
if (fType.isPrimitive()) {
switch (fType.descriptorString()) {
case "B" -> f.setByte(obj, ((Byte) value).byteValue());
case "C" -> f.setChar(obj, ((Character) value).charValue());
case "D" -> f.setDouble(obj, ((Double) value).doubleValue());
case "F" -> f.setFloat(obj, ((Float) value).floatValue());
case "I" -> f.setInt(obj, ((Integer) value).intValue());
case "J" -> f.setLong(obj, ((Long) value).longValue());
case "S" -> f.setShort(obj, ((Short) value).shortValue());
case "Z" -> f.setBoolean(obj, ((Boolean) value).booleanValue());
}
// test null value only if it's primitive type
try {
f.set(obj, null);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
Object badValue = new NegativeTest();
try {
f.set(obj, badValue);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@DataProvider(name = "readOnlyFinalFields")
private Object[][] readOnlyFinalFields() {
Object obj = INSTANCE;
return new Object[][]{
// instance final fields
new Object[]{fi_field, obj, Integer.valueOf(10)},
new Object[]{fc_field, obj, Character.valueOf('c')},
new Object[]{fb_field, obj, Byte.valueOf((byte)1)},
new Object[]{fs_field, obj, Short.valueOf((short)2)},
new Object[]{fl_field, obj, Long.valueOf(1000)},
new Object[]{fd_field, obj, Double.valueOf(1.2)},
new Object[]{ff_field, obj, Float.valueOf(2.5f)},
new Object[]{fz_field, obj, Boolean.valueOf(true)},
new Object[]{fo_field, obj, "good-value"},
// static final fields
new Object[]{sfi_field, null, Integer.valueOf(10)},
new Object[]{sfc_field, null, Character.valueOf('c')},
new Object[]{sfb_field, null, Byte.valueOf((byte)1)},
new Object[]{sfs_field, null, Short.valueOf((short)2)},
new Object[]{sfl_field, null, Long.valueOf(1000)},
new Object[]{sfd_field, null, Double.valueOf(1.2)},
new Object[]{sff_field, null, Float.valueOf(2.5f)},
new Object[]{sfz_field, null, Boolean.valueOf(true)},
new Object[]{sfo_field, null, "good-value"},
new Object[]{override_sfi_field, null, Integer.valueOf(10)},
new Object[]{override_sfc_field, null, Character.valueOf('c')},
new Object[]{override_sfb_field, null, Byte.valueOf((byte)1)},
new Object[]{override_sfs_field, null, Short.valueOf((short)2)},
new Object[]{override_sfl_field, null, Long.valueOf(1000)},
new Object[]{override_sfd_field, null, Double.valueOf(1.2)},
new Object[]{override_sff_field, null, Float.valueOf(2.5f)},
new Object[]{override_sfz_field, null, Boolean.valueOf(true)},
new Object[]{override_sfo_field, null, "good-value"},
};
}
/*
* Test Field::set on a read-only final field.
* IllegalAccessException is thrown regardless of whether the value
* is of a bad type or not.
*/
@Test(dataProvider = "readOnlyFinalFields")
public void testSetValueOnFinalField(Field f, Object obj, Object value) {
assertTrue(Modifier.isFinal(f.getModifiers()));
try {
f.set(obj, value);
fail("expected IllegalAccessException");
} catch (IllegalAccessException e) {
// expected
}
Class<?> fType = f.getType();
if (fType.isPrimitive()) {
try {
switch (fType.descriptorString()) {
case "B" -> f.setByte(obj, ((Byte)value).byteValue());
case "C" -> f.setChar(obj, ((Character)value).charValue());
case "D" -> f.setDouble(obj, ((Double)value).doubleValue());
case "F" -> f.setFloat(obj, ((Float)value).floatValue());
case "I" -> f.setInt(obj, ((Integer)value).intValue());
case "J" -> f.setLong(obj, ((Long)value).longValue());
case "S" -> f.setShort(obj, ((Short)value).shortValue());
case "Z" -> f.setBoolean(obj, ((Boolean)value).booleanValue());
}
fail("expected IllegalAccessException");
} catch (IllegalAccessException e) {
// expected
}
// test null value only if it's primitive type
try {
f.set(obj, null);
fail("expected IllegalAccessException");
} catch (IllegalAccessException e) {
// expected
}
}
Object badValue = new NegativeTest();
try {
f.set(obj, badValue);
fail("expected IllegalAccessException");
} catch (IllegalAccessException e) {
// expected
}
}
@DataProvider(name = "finalInstanceFields")
private Object[][] finalInstanceFields() {
return new Object[][]{
new Object[]{fi_field, Integer.valueOf(10)},
new Object[]{fc_field, Character.valueOf('c')},
new Object[]{fb_field, Byte.valueOf((byte) 1)},
new Object[]{fs_field, Short.valueOf((short) 2)},
new Object[]{fl_field, Long.valueOf(1000)},
new Object[]{fd_field, Double.valueOf(1.2)},
new Object[]{ff_field, Float.valueOf(2.5f)},
new Object[]{fz_field, Boolean.valueOf(true)},
new Object[]{fo_field, "good-value"},
};
}
/*
* Test Field::set on a final instance field with either a bad receiver
* or null. IllegalArgumentException is thrown if the receiver is of
* a bad type. NullPointerException is thrown if the receiver is null.
* The receiver is checked before the access check is performed and
* also before the value is checked.
*/
@Test(dataProvider = "finalInstanceFields")
public void testReceiverOnFinalField(Field f, Object value) {
assertTrue(Modifier.isFinal(f.getModifiers()));
Object badReceiver = new NegativeTest();
// set the field with a bad receiver with a good value
try {
f.set(badReceiver, value);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e);
}
// set the field with a bad receiver with a bad value
Object badValue = new NegativeTest();
try {
f.set(badReceiver, badValue);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e);
}
// set the field with a null receiver with a good value
try {
f.set(null, value);
fail("expected NullPointerException");
} catch (NullPointerException e) {
// expected
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e);
}
// set the field with a null receiver with a bad value
try {
f.set(null, badValue);
fail("expected NullPointerException");
} catch (NullPointerException e) {
// expected
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e);
}
Class<?> fType = f.getType();
if (fType.isPrimitive()) {
// test bad receiver
try {
switch (fType.descriptorString()) {
case "B" -> f.setByte(badReceiver, ((Byte) value).byteValue());
case "C" -> f.setChar(badReceiver, ((Character) value).charValue());
case "D" -> f.setDouble(badReceiver, ((Double) value).doubleValue());
case "F" -> f.setFloat(badReceiver, ((Float) value).floatValue());
case "I" -> f.setInt(badReceiver, ((Integer) value).intValue());
case "J" -> f.setLong(badReceiver, ((Long) value).longValue());
case "S" -> f.setShort(badReceiver, ((Short) value).shortValue());
case "Z" -> f.setBoolean(badReceiver, ((Boolean) value).booleanValue());
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e);
}
// test null receiver
try {
switch (fType.descriptorString()) {
case "B" -> f.setByte(null, ((Byte) value).byteValue());
case "C" -> f.setChar(null, ((Character) value).charValue());
case "D" -> f.setDouble(null, ((Double) value).doubleValue());
case "F" -> f.setFloat(null, ((Float) value).floatValue());
case "I" -> f.setInt(null, ((Integer) value).intValue());
case "J" -> f.setLong(null, ((Long) value).longValue());
case "S" -> f.setShort(null, ((Short) value).shortValue());
case "Z" -> f.setBoolean(null, ((Boolean) value).booleanValue());
}
} catch (NullPointerException e) {
// expected
} catch (IllegalAccessException e) {
throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e);
}
}
}
}