Repository: junit-team/junit5 (language: java)

Issue:
Introduce `ReflectionSupport.makeAccessible(Field)` for third-party use
## Steps to reproduce

The commit abb5ed16be3a9ce552f4a45c11264ded608ae9da removes the method `ReflectionUtils.makeAccessible(AccessibleObject)`, but it is being used by `DropwizardExtensionsSupport`.

In `pom.xml`:

```xml
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.11.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.dropwizard</groupId>
      <artifactId>dropwizard-testing</artifactId>
      <version>4.0.7</version>
      <scope>test</scope>
    </dependency>
```

In the test class:

```java
@ExtendWith(DropwizardExtensionsSupport.class)
class SampleTest {
  @Path("/test-resource")
  static class TestResource {
    @GET
    public String get() {
      throw new RuntimeException("No object found");
    }
  }

  private static final ResourceExtension sResources = ResourceExtension.builder()
      .addResource(new TestResource())
      .build();

  @Test
  void testException() {
    Response response = sResources.target("/test-resource").request().get();
    assertEquals(500, response.getStatus(), "Status code does not match");
  }
}
```

Run `mvn test`.

Full stacktrace:

```
java.lang.Exception: java.lang.NoSuchMethodError: 'java.lang.reflect.AccessibleObject org.junit.platform.commons.util.ReflectionUtils.makeAccessible(java.lang.reflect.AccessibleObject)'
	at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.beforeAll(DropwizardExtensionsSupport.java:87)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	Suppressed: java.lang.Exception: java.lang.NoSuchMethodError: 'java.lang.reflect.AccessibleObject org.junit.platform.commons.util.ReflectionUtils.makeAccessible(java.lang.reflect.AccessibleObject)'
		at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.afterAll(DropwizardExtensionsSupport.java:40)
		... 1 more
	Caused by: java.lang.NoSuchMethodError: 'java.lang.reflect.AccessibleObject org.junit.platform.commons.util.ReflectionUtils.makeAccessible(java.lang.reflect.AccessibleObject)'
		at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.getDropwizardExtension(DropwizardExtensionsSupport.java:149)
		at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.afterAll(DropwizardExtensionsSupport.java:50)
		at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.afterAll(DropwizardExtensionsSupport.java:36)
		... 1 more
Caused by: java.lang.NoSuchMethodError: 'java.lang.reflect.AccessibleObject org.junit.platform.commons.util.ReflectionUtils.makeAccessible(java.lang.reflect.AccessibleObject)'
	at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.getDropwizardExtension(DropwizardExtensionsSupport.java:149)
	at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.beforeAll(DropwizardExtensionsSupport.java:97)
	at io.dropwizard.testing.junit5.DropwizardExtensionsSupport.beforeAll(DropwizardExtensionsSupport.java:83)
	... 1 more
```

## Context

 - Used versions (Jupiter/Vintage/Platform): junit-jupiter 5.11.0
 - Build Tool/IDE: Apache Maven 3.6.3

## Deliverables

- [x] Introduce a supported, public alternative to `ReflectionUtils.makeAccessible`



Discussion / hints:
`ReflectionUtils` is annotated with `@API(status = INTERNAL)`. Thus, it's an internal class and shouldn't be used by third-party projects like Dropwizard. That being said, I see @joschi has already [updated](https://github.com/dropwizard/dropwizard/pull/9154) Dropwizard's JUnit dependency to 5.11.0 which caused it to be recompiled now using the `ReflectionUtils.makeAccessible(Field)` method rather than the no longer existing `ReflectionUtils.makeAccessible(AccessibleObject)` one. I think the quickest way to resolve the issue is to release a patch version of Dropwizard.

@joschi Do you think that would be feasible?

To avoid this in the future, we should introduce a `makeAccessible(Field)` method in `ReflectionSupport` which is intended to be used by third parties.

Fix patch:
diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.1.adoc
index cfeb3559c0f4..48a5c8fdf324 100644
--- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.1.adoc
+++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.1.adoc
@@ -26,7 +26,8 @@ JUnit repository on GitHub.
 [[release-notes-5.11.1-junit-platform-new-features-and-improvements]]
 ==== New Features and Improvements
 
-* ❓
+* Introduce `ReflectionSupport.makeAccessible(Field)` for third-party use rather than
+  calling the internal `ReflectionUtils.makeAccessible(Field)` method directly.
 
 
 [[release-notes-5.11.1-junit-jupiter]]
diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java
index ac5831d88329..3949e3f39b87 100644
--- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java
+++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java
@@ -15,9 +15,9 @@
 import static org.junit.jupiter.api.io.CleanupMode.DEFAULT;
 import static org.junit.jupiter.api.io.CleanupMode.NEVER;
 import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS;
+import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible;
 import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields;
 import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation;
-import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java b/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java
index ef277f590fcd..339c9ed47df4 100644
--- a/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java
+++ b/junit-jupiter-migrationsupport/src/main/java/org/junit/jupiter/migrationsupport/rules/member/TestRuleAnnotatedField.java
@@ -11,7 +11,7 @@
 package org.junit.jupiter.migrationsupport.rules.member;
 
 import static org.apiguardian.api.API.Status.INTERNAL;
-import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
+import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible;
 
 import java.lang.reflect.Field;
 
diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java
index 6d63e015fccc..af578f1ff4ff 100644
--- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java
+++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java
@@ -652,4 +652,21 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
 		return ReflectionUtils.streamNestedClasses(clazz, predicate);
 	}
 
+	/**
+	 * Make the supplied field accessible via reflection.
+	 *
+	 * <p>If you're looking for similar functionality for constructors or
+	 * methods, consider using {@link #newInstance(Class, Object...)} or
+	 * {@link #invokeMethod(Method, Object, Object...)}.
+	 *
+	 * @param field the field to make accessible; never {@code null}
+	 * @return the supplied field
+	 * @since 1.11.1
+	 * @see Field#setAccessible(boolean)
+	 */
+	@API(status = EXPERIMENTAL, since = "1.11.1")
+	public static Field makeAccessible(Field field) {
+		return ReflectionUtils.makeAccessible(Preconditions.notNull(field, "field must not be null"));
+	}
+
 }


Test patch:
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java
index 2a748e280283..982ced8e1569 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java
@@ -15,8 +15,8 @@
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.DynamicTest.dynamicTest;
 import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT;
+import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible;
 import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields;
-import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
 import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
 import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
 import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java
index 23e4cc9ec564..ce9be391a7a4 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ProgrammaticExtensionRegistrationTests.java
@@ -16,7 +16,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
-import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
+import static org.junit.platform.commons.support.ReflectionSupport.makeAccessible;
 import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
 import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
 import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;