From 479931cf8f2130034e6444c94d05c8adabf661df Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 5 Dec 2017 15:46:01 -0800 Subject: [PATCH] Introduce overloaded readFieldValue() variants in ReflectionUtils --- .../commons/util/ReflectionUtils.java | 46 ++++++++++++++++++- .../commons/util/ReflectionUtilsTests.java | 43 ++++++++++++++--- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index f794101b092..fc3e41a381e 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -360,7 +360,7 @@ public static T newInstance(Constructor constructor, Object... args) { } /** - * Read the value of a potentially inaccessible field. + * Read the value of a potentially inaccessible or nonexistent field. * *

If the field does not exist, an exception occurs while reading it, or * the value of the field is {@code null}, an empty {@link Optional} is @@ -370,13 +370,55 @@ public static T newInstance(Constructor constructor, Object... args) { * @param fieldName the name of the field; never {@code null} or empty * @param instance the instance from where the value is to be read; may * be {@code null} for a static field + * @see #readFieldValue(Field) + * @see #readFieldValue(Field, Object) */ public static Optional readFieldValue(Class clazz, String fieldName, T instance) { Preconditions.notNull(clazz, "Class must not be null"); Preconditions.notBlank(fieldName, "Field name must not be null or blank"); + Field field = null; + try { + field = makeAccessible(clazz.getDeclaredField(fieldName)); + } + catch (Throwable t) { + BlacklistedExceptions.rethrowIfBlacklisted(t); + return Optional.empty(); + } + return readFieldValue(field, instance); + } + + /** + * Read the value of a potentially inaccessible static field. + * + *

If an exception occurs while reading the field or if the value of the + * field is {@code null}, an empty {@link Optional} is returned. + * + * @param field the field to read; never {@code null} + * @see #readFieldValue(Field, Object) + * @see #readFieldValue(Class, String, Object) + */ + public static Optional readFieldValue(Field field) { + return readFieldValue(field, null); + } + + /** + * Read the value of a potentially inaccessible field. + * + *

If an exception occurs while reading the field or if the value of the + * field is {@code null}, an empty {@link Optional} is returned. + * + * @param field the field to read; never {@code null} + * @param instance the instance from which the value is to be read; may + * be {@code null} for a static field + * @see #readFieldValue(Field) + * @see #readFieldValue(Class, String, Object) + */ + public static Optional readFieldValue(Field field, T instance) { + Preconditions.notNull(field, "Field must not be null"); + try { - Field field = makeAccessible(clazz.getDeclaredField(fieldName)); + makeAccessible(field); return Optional.ofNullable(field.get(instance)); } catch (Throwable t) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 97e9fd6e93f..52810faddaa 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.file.Files; @@ -162,13 +163,34 @@ void newInstance() { } @Test - void readFieldValueOfExistingField() { - assertThat(readFieldValue(MyClass.class, "value", new MyClass(42))).contains(42); + void readFieldValueOfNonexistentStaticField() { + assertThat(readFieldValue(MyClass.class, "doesNotExist", null)).isNotPresent(); + assertThat(readFieldValue(MySubClass.class, "staticField", null)).isNotPresent(); } @Test - void readFieldValueOfMissingField() { - assertThat(readFieldValue(MyClass.class, "doesNotExist", new MyClass(42))).isEmpty(); + void readFieldValueOfNonexistentInstanceField() { + assertThat(readFieldValue(MyClass.class, "doesNotExist", new MyClass(42))).isNotPresent(); + assertThat(readFieldValue(MyClass.class, "doesNotExist", new MySubClass(42))).isNotPresent(); + } + + @Test + void readFieldValueOfExistingStaticField() throws Exception { + assertThat(readFieldValue(MyClass.class, "staticField", null)).contains(42); + + Field field = MyClass.class.getDeclaredField("staticField"); + assertThat(readFieldValue(field)).contains(42); + assertThat(readFieldValue(field, null)).contains(42); + } + + @Test + void readFieldValueOfExistingInstanceField() throws Exception { + MyClass instance = new MyClass(42); + assertThat(readFieldValue(MyClass.class, "instanceField", instance)).contains(42); + + Field field = MyClass.class.getDeclaredField("instanceField"); + assertThat(readFieldValue(field, instance)).contains(42); + assertThat(readFieldValue(field, null)).isNotPresent(); } @Test @@ -1136,10 +1158,19 @@ static class Exploder { static class MyClass { - final int value; + static final int staticField = 42; + + final int instanceField; MyClass(int value) { - this.value = value; + this.instanceField = value; + } + } + + static class MySubClass extends MyClass { + + MySubClass(int value) { + super(value); } }