/* * 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); } } } }