diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
index f625faac7f17..aefbba1f2adc 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
@@ -52,7 +50,7 @@ public boolean supportsTestTemplate(ExtensionContext context) {
		ParameterizedTestMethodContext methodContext =

diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc
index c37680f13b5d..e23dcb707c34 100644
--- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc
+++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc
@@ -50,6 +50,10 @@ JUnit repository on GitHub.
 * In a `@ParameterizedTest` method, a `null` value can now be supplied for Java Date/Time
   types such as `LocalDate` if the new `nullable` attribute in
   `@JavaTimeConversionPattern` is set to `true`.
+* `ArgumentsProvider` (declared via `@ArgumentsSource`), `ArgumentConverter` (declared via
+  `@ConvertWith`), and `ArgumentsAggregator` (declared via `@AggregateWith`)
+  implementations can now use constructor injection from registered `ParameterResolver`
+  extensions.

 [[release-notes-5.12.0-M1-junit-vintage]]
diff --git a/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java b/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java
index bc296054ec36..e3e7df3c58c2 100644
--- a/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java
+++ b/junit-jupiter-params/src/jmh/java/org/junit/jupiter/params/ParameterizedTestNameFormatterBenchmarks.java
@@ -47,7 +47,8 @@ public void formatTestNames(Blackhole blackhole) throws Exception {
 		var formatter = new ParameterizedTestNameFormatter(
 			ParameterizedTest.DISPLAY_NAME_PLACEHOLDER + " " + ParameterizedTest.DEFAULT_DISPLAY_NAME + " ({0})",
 			"displayName",
-			new ParameterizedTestMethodContext(TestCase.class.getDeclaredMethod("parameterizedTest", int.class)), 512);
+			new ParameterizedTestMethodContext(TestCase.class.getDeclaredMethod("parameterizedTest", int.class), null),
+			512);
 		for (int i = 0; i < argumentsList.size(); i++) {
 			Arguments arguments = argumentsList.get(i);
 			blackhole.consume(formatter.format(i, arguments, arguments.get()));
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
index f625faac7f17..aefbba1f2adc 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
@@ -26,8 +26,6 @@
 import org.junit.jupiter.params.provider.ArgumentsProvider;
 import org.junit.jupiter.params.provider.ArgumentsSource;
 import org.junit.jupiter.params.support.AnnotationConsumerInitializer;
-import org.junit.platform.commons.JUnitException;
-import org.junit.platform.commons.support.ReflectionSupport;
 import org.junit.platform.commons.util.ExceptionUtils;
 import org.junit.platform.commons.util.Preconditions;

@@ -52,7 +50,7 @@ public boolean supportsTestTemplate(ExtensionContext context) {
 			return false;
 		}

-		ParameterizedTestMethodContext methodContext = new ParameterizedTestMethodContext(testMethod);
+		ParameterizedTestMethodContext methodContext = new ParameterizedTestMethodContext(testMethod, context);

 		Preconditions.condition(methodContext.hasPotentiallyValidSignature(),
 			() -> String.format(
@@ -84,7 +82,7 @@ public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContex
 		return findRepeatableAnnotations(templateMethod, ArgumentsSource.class)
 				.stream()
 				.map(ArgumentsSource::value)
-				.map(this::instantiateArgumentsProvider)
+				.map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentsProvider.class, clazz, extensionContext))
 				.map(provider -> AnnotationConsumerInitializer.initialize(templateMethod, provider))
 				.flatMap(provider -> arguments(provider, extensionContext))
 				.map(arguments -> {
@@ -97,23 +95,6 @@ public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContex
 		// @formatter:on
 	}

-	@SuppressWarnings("ConstantConditions")
-	private ArgumentsProvider instantiateArgumentsProvider(Class<? extends ArgumentsProvider> clazz) {
-		try {
-			return ReflectionSupport.newInstance(clazz);
-		}
-		catch (Exception ex) {
-			if (ex instanceof NoSuchMethodException) {
-				String message = String.format("Failed to find a no-argument constructor for ArgumentsProvider [%s]. "
-						+ "Please ensure that a no-argument constructor exists and "
-						+ "that the class is either a top-level class or a static nested class",
-					clazz.getName());
-				throw new JUnitException(message, ex);
-			}
-			throw ex;
-		}
-	}
-
 	private ExtensionContext.Store getStore(ExtensionContext context) {
 		return context.getStore(Namespace.create(ParameterizedTestExtension.class, context.getRequiredTestMethod()));
 	}
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java
index 1b88b3a14467..a7469d4f4003 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestMethodContext.java
@@ -20,6 +20,7 @@
 import java.util.List;
 import java.util.Optional;

+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.params.aggregator.AggregateWith;
@@ -31,7 +32,6 @@
 import org.junit.jupiter.params.converter.DefaultArgumentConverter;
 import org.junit.jupiter.params.support.AnnotationConsumerInitializer;
 import org.junit.platform.commons.support.AnnotationSupport;
-import org.junit.platform.commons.support.ReflectionSupport;
 import org.junit.platform.commons.util.StringUtils;

 /**
@@ -43,16 +43,18 @@
 class ParameterizedTestMethodContext {

 	private final Parameter[] parameters;
+	private final ExtensionContext extensionContext;
 	private final Resolver[] resolvers;
 	private final List<ResolverType> resolverTypes;

-	ParameterizedTestMethodContext(Method testMethod) {
+	ParameterizedTestMethodContext(Method testMethod, ExtensionContext extensionContext) {
 		this.parameters = testMethod.getParameters();
 		this.resolvers = new Resolver[this.parameters.length];
 		this.resolverTypes = new ArrayList<>(this.parameters.length);
 		for (Parameter parameter : this.parameters) {
 			this.resolverTypes.add(isAggregator(parameter) ? AGGREGATOR : CONVERTER);
 		}
+		this.extensionContext = extensionContext;
 	}

 	/**
@@ -167,7 +169,7 @@ Object resolve(ParameterContext parameterContext, Object[] arguments, int invoca
 	private Resolver getResolver(ParameterContext parameterContext) {
 		int index = parameterContext.getIndex();
 		if (resolvers[index] == null) {
-			resolvers[index] = resolverTypes.get(index).createResolver(parameterContext);
+			resolvers[index] = resolverTypes.get(index).createResolver(parameterContext, extensionContext);
 		}
 		return resolvers[index];
 	}
@@ -176,11 +178,11 @@ enum ResolverType {

 		CONVERTER {
 			@Override
-			Resolver createResolver(ParameterContext parameterContext) {
+			Resolver createResolver(ParameterContext parameterContext, ExtensionContext extensionContext) {
 				try { // @formatter:off
 					return AnnotationSupport.findAnnotation(parameterContext.getParameter(), ConvertWith.class)
 							.map(ConvertWith::value)
-							.map(clazz -> (ArgumentConverter) ReflectionSupport.newInstance(clazz))
+							.map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentConverter.class, clazz, extensionContext))
 							.map(converter -> AnnotationConsumerInitializer.initialize(parameterContext.getParameter(), converter))
 							.map(Converter::new)
 							.orElse(Converter.DEFAULT);
@@ -193,11 +195,11 @@ Resolver createResolver(ParameterContext parameterContext) {

 		AGGREGATOR {
 			@Override
-			Resolver createResolver(ParameterContext parameterContext) {
+			Resolver createResolver(ParameterContext parameterContext, ExtensionContext extensionContext) {
 				try { // @formatter:off
 					return AnnotationSupport.findAnnotation(parameterContext.getParameter(), AggregateWith.class)
 							.map(AggregateWith::value)
-							.map(clazz -> (ArgumentsAggregator) ReflectionSupport.newInstance(clazz))
+							.map(clazz -> ParameterizedTestSpiInstantiator.instantiate(ArgumentsAggregator.class, clazz, extensionContext))
 							.map(Aggregator::new)
 							.orElse(Aggregator.DEFAULT);
 				} // @formatter:on
@@ -207,7 +209,7 @@ Resolver createResolver(ParameterContext parameterContext) {
 			}
 		};

-		abstract Resolver createResolver(ParameterContext parameterContext);
+		abstract Resolver createResolver(ParameterContext parameterContext, ExtensionContext extensionContext);

 	}

diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java
new file mode 100644
index 000000000000..24c7163ac27a
--- /dev/null
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015-2024 the original author or authors.
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * https://www.eclipse.org/legal/epl-v20.html
+ */
+
+package org.junit.jupiter.params;
+
+import static org.junit.platform.commons.util.CollectionUtils.getFirstElement;
+
+import java.lang.reflect.Constructor;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.platform.commons.JUnitException;
+import org.junit.platform.commons.PreconditionViolationException;
+import org.junit.platform.commons.util.Preconditions;
+import org.junit.platform.commons.util.ReflectionUtils;
+
+/**
+ * @since 5.12
+ */
+class ParameterizedTestSpiInstantiator {
+
+	static <T> T instantiate(Class<T> spiInterface, Class<? extends T> implementationClass,
+			ExtensionContext extensionContext) {
+		return extensionContext.getExecutableInvoker() //
+				.invoke(findConstructor(spiInterface, implementationClass));
+	}
+
+	/**
+	 * Find the "best" constructor for the supplied class.
+	 *
+	 *
For backward compatibility, it first checks for a default constructor
+	 * which takes precedence over any other constructor. If no default
+	 * constructor is found, it checks for a single constructor and returns it.
+	 */
+	private static <T, V extends T> Constructor<? extends V> findConstructor(Class<T> spiInterface,
+			Class<V> implementationClass) {
+
+		Preconditions.condition(!ReflectionUtils.isInnerClass(implementationClass),
+			() -> String.format("The %s [%s] must be either a top-level class or a static nested class",
+				spiInterface.getSimpleName(), implementationClass.getName()));
+
+		return findDefaultConstructor(implementationClass) //
+				.orElseGet(() -> findSingleConstructor(spiInterface, implementationClass));
+	}
+
+	@SuppressWarnings("unchecked")
+	private static <T> Optional<Constructor<T>> findDefaultConstructor(Class<T> clazz) {
+		return getFirstElement(ReflectionUtils.findConstructors(clazz, it -> it.getParameterCount() == 0)) //
+				.map(it -> (Constructor<T>) it);
+	}
+
+	private static <T, V extends T> Constructor<V> findSingleConstructor(Class<T> spiInterface,
+			Class<V> implementationClass) {
+
+		try {
+			return ReflectionUtils.getDeclaredConstructor(implementationClass);
+		}
+		catch (PreconditionViolationException ex) {
+			String message = String.format(
+				"Failed to find constructor for %s [%s]. "
+						+ "Please ensure that a no-argument or a single constructor exists.",
+				spiInterface.getSimpleName(), implementationClass.getName());
+			throw new JUnitException(message);
+		}
+	}
+}
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java
index e4ed9803f09f..c82d12cda961 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/ArgumentsAggregator.java
@@ -14,6 +14,7 @@

 import org.apiguardian.api.API;
 import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolver;

 /**
  * {@code ArgumentsAggregator} is an abstraction for the aggregation of arguments
@@ -33,10 +34,11 @@
  * in a CSV file into a domain object such as a {@code Person}, {@code Address},
  * {@code Order}, etc.
  *
- *
Implementations must provide a no-args constructor and should not make any
- * assumptions regarding when they are instantiated or how often they are called.
- * Since instances may potentially be cached and called from different threads,
- * they should be thread-safe and designed to be used as singletons.
+ *
Implementations must provide a no-args constructor or a single unambiguous
+ * constructor to use {@linkplain ParameterResolver parameter resolution}. They
+ * should not make any assumptions regarding when they are instantiated or how
+ * often they are called. Since instances may potentially be cached and called
+ * from different threads, they should be thread-safe.
  *
  * @since 5.2
  * @see AggregateWith
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java
index 46f7e9a84b79..b18d96887069 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java
@@ -14,6 +14,7 @@

 import org.apiguardian.api.API;
 import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolver;

 /**
  * {@code ArgumentConverter} is an abstraction that allows an input object to
@@ -24,10 +25,11 @@
  * method with the help of a
  * {@link org.junit.jupiter.params.converter.ConvertWith @ConvertWith} annotation.
  *
- *
Implementations must provide a no-args constructor and should not make any
- * assumptions regarding when they are instantiated or how often they are called.
- * Since instances may potentially be cached and called from different threads,
- * they should be thread-safe and designed to be used as singletons.
+ *
Implementations must provide a no-args constructor or a single unambiguous
+ * constructor to use {@linkplain ParameterResolver parameter resolution}. They
+ * should not make any assumptions regarding when they are instantiated or how
+ * often they are called. Since instances may potentially be cached and called
+ * from different threads, they should be thread-safe.
  *
  *
Extend {@link SimpleArgumentConverter} if your implementation only needs
  * to know the target type and does not need access to the {@link ParameterContext}
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java
index 689517d607b8..c18d100ad3c5 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsProvider.java
@@ -16,6 +16,7 @@

 import org.apiguardian.api.API;
 import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterResolver;

 /**
  * An {@code ArgumentsProvider} is responsible for {@linkplain #provideArguments
@@ -25,7 +26,8 @@
  *
An {@code ArgumentsProvider} can be registered via the
  * {@link ArgumentsSource @ArgumentsSource} annotation.
  *
- *
Implementations must provide a no-args constructor.
+ *
Implementations must provide a no-args constructor or a single unambiguous
+ * constructor to use {@linkplain ParameterResolver parameter resolution}.
  *
  * @since 5.0
  * @see org.junit.jupiter.params.ParameterizedTest

Use the `ParameterizedTestSpiInstantiator` to create argument converters and aggregators instead of directly instantiating them, and pass the extension context to the resolver creation methods.

Prompt:
The following is the text of a github issue and related comments for this repository:

Add constructor injection support for `ArgumentsProvider`, `ArgumentConverter`, and `ArgumentsAggregator`
It is possible to provide parameters to the constructor of a test class, and also to a method used by `@ParameterizedTest`/`@MethodSource`.

Request: Be able to provide parameters to the constructor of an `ArgumentsProvider` implementation.

Sample:

```java
@ExtendWith(MyExtension.class) // this extension provides values for type 'Pojo' parameters
public class WithArgumentsProvider {

    @Nested
    public class NestedTest1 {

        @ParameterizedTest
        @ArgumentsSource(MyArgumentsProvider.class)
        public void test1(String a) {
            System.out.println("NestedTest1 - Test1: " + a);
        }

    }

    @Nested
    public class NestedTest2 {

        @ParameterizedTest
        @ArgumentsSource(MyArgumentsProvider.class)
        public void test2(String a) {
            System.out.println("NestedTest2 - Test2: " + a);
        }

    }

    public static class MyArgumentsProvider implements ArgumentsProvider {

        public MyArgumentsProvider(Pojo pojo) {
            // ...
        }

        @Override
        public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
            return Stream.of("a", "b", "c").map(Arguments::of);
        }

    }

}
```

Dev hint: https://github.com/junit-team/junit5/blob/e8c92f8cdeafe80ae485da4b4d8bd77f7b33e345/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java#L87

In the meantime, as a workaround, you can do this:

```
@ExtendWith(WithArgumentsProvider.MyExtension.class) // this extension provides values for type 'Pojo' parameters
public class WithArgumentsProvider {

    @Nested
    public class NestedTest1 {

        @ParameterizedTest
        @ArgumentsSource(MyArgumentsProvider.class)
        public void test1(String a) {
            System.out.println("NestedTest1 - Test1: " + a);
        }

    }

    @Nested
    public class NestedTest2 {

        @ParameterizedTest
        @ArgumentsSource(MyArgumentsProvider.class)
        public void test2(String a) {
            System.out.println("NestedTest2 - Test2: " + a);
        }

    }

    public static class MyArgumentsProvider implements ArgumentsProvider {

        @SuppressWarnings("unchecked")
		@Override
        public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception {
            Method method = getClass().getDeclaredMethod("provideArguments", Pojo.class);
			return (Stream<? extends Arguments>) context.getExecutableInvoker().invoke(method, this);
        }

        Stream<? extends Arguments> provideArguments(Pojo pojo) {
            return Stream.of(Arguments.of(pojo.toString()));
        }
    }

}
```

I think the only reason that's not implemented is because @ParameterizedTest is implemented as an extension and predates ExecutableInvoker. Adding support should be as simple as changing

junit5/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java

Line 103 in c24d9a6
```
 return ReflectionSupport.newInstance(clazz);
```

to use context.getExecutableInvoker().invoke(clazz.getDeclaredConstructor()).

Resolve the issue described above. Do not modify tests or user code. The issue can be resolved by modifying the actual library/application code. Make the minimal changes to resolve the issue while adhering to the specification and coding style of the codebase.

diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
index f625faac7f17..aefbba1f2adc 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestExtension.java
@@ -52,7 +50,7 @@ public boolean supportsTestTemplate(ExtensionContext context) {
 			return false;
 		}

-		ParameterizedTestMethodContext methodContext = new ParameterizedTestMethodContext(testMethod);
+		ParameterizedTestMethodContext methodContext = new ParameterizedTestMethodContext(testMethod, context);

 		Preconditions.condition(methodContext.hasPotentiallyValidSignature(),
 			() -> String.format(

diff --git a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
index 463faad468c8..2dc985d9a872 100644
--- a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
+++ b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
@@ -1984,6 +1984,15 @@ If you wish to implement a custom `ArgumentsProvider` that also consumes an anno
 (like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`),
 you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class.

+Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case
+they need to be resolved by a registered `ParameterResolver` as demonstrated in the
+following example.
+
+[source,java,indent=0]
+----
+include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example]
+----
+
 [[writing-tests-parameterized-repeatable-sources]]
 ===== Multiple sources using repeatable annotations
 Repeatable annotations provide a convenient way to specify multiple sources from
diff --git a/documentation/src/test/java/example/ParameterizedTestDemo.java b/documentation/src/test/java/example/ParameterizedTestDemo.java
index 4d99f22c9311..9027b86d67e4 100644
--- a/documentation/src/test/java/example/ParameterizedTestDemo.java
+++ b/documentation/src/test/java/example/ParameterizedTestDemo.java
@@ -348,6 +348,29 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
 	}
 	// end::ArgumentsProvider_example[]

+	@ParameterizedTest
+	@ArgumentsSource(MyArgumentsProviderWithConstructorInjection.class)
+	void testWithArgumentsSourceWithConstructorInjection(String argument) {
+		assertNotNull(argument);
+	}
+
+	static
+	// tag::ArgumentsProviderWithConstructorInjection_example[]
+	public class MyArgumentsProviderWithConstructorInjection implements ArgumentsProvider {
+
+		private final TestInfo testInfo;
+
+		public MyArgumentsProviderWithConstructorInjection(TestInfo testInfo) {
+			this.testInfo = testInfo;
+		}
+
+		@Override
+		public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
+			return Stream.of(Arguments.of(testInfo.getDisplayName()));
+		}
+	}
+	// end::ArgumentsProviderWithConstructorInjection_example[]
+
 	// tag::ParameterResolver_example[]
 	@BeforeEach
 	void beforeEach(TestInfo testInfo) {
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java
index 69db68af81ba..3172140691ae 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestExtensionTests.java
@@ -19,6 +19,7 @@

 import java.io.FileNotFoundException;
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Map;
@@ -40,6 +41,7 @@
 import org.junit.jupiter.params.provider.ArgumentsSource;
 import org.junit.platform.commons.JUnitException;
 import org.junit.platform.commons.PreconditionViolationException;
+import org.junit.platform.commons.util.ReflectionUtils;
 import org.junit.platform.engine.support.store.NamespacedHierarchicalStore;

 /**
@@ -150,11 +152,14 @@ void throwsExceptionWhenArgumentsProviderIsNotStatic() {

 		var exception = assertThrows(JUnitException.class, stream::toArray);

-		assertArgumentsProviderInstantiationException(exception, NonStaticArgumentsProvider.class);
+		assertThat(exception) //
+				.hasMessage(String.format(
+					"The ArgumentsProvider [%s] must be either a top-level class or a static nested class",
+					NonStaticArgumentsProvider.class.getName()));
 	}

 	@Test
-	void throwsExceptionWhenArgumentsProviderDoesNotContainNoArgumentConstructor() {
+	void throwsExceptionWhenArgumentsProviderDoesNotContainUnambiguousConstructor() {
 		var extensionContextWithAnnotatedTestMethod = getExtensionContextReturningSingleMethod(
 			new MissingNoArgumentsConstructorArgumentsProviderTestCase());

@@ -163,15 +168,11 @@ void throwsExceptionWhenArgumentsProviderDoesNotContainNoArgumentConstructor() {

 		var exception = assertThrows(JUnitException.class, stream::toArray);

-		assertArgumentsProviderInstantiationException(exception, MissingNoArgumentsConstructorArgumentsProvider.class);
-	}
-
-	private <T> void assertArgumentsProviderInstantiationException(JUnitException exception, Class<T> clazz) {
-		assertThat(exception).hasMessage(
-			String.format("Failed to find a no-argument constructor for ArgumentsProvider [%s]. "
-					+ "Please ensure that a no-argument constructor exists and "
-					+ "that the class is either a top-level class or a static nested class",
-				clazz.getName()));
+		String className = AmbiguousConstructorArgumentsProvider.class.getName();
+		assertThat(exception) //
+				.hasMessage(String.format("Failed to find constructor for ArgumentsProvider [%s]. "
+						+ "Please ensure that a no-argument or a single constructor exists.",
+					className));
 	}

 	private ExtensionContext getExtensionContextReturningSingleMethod(Object testCase) {
@@ -277,7 +278,17 @@ public ExecutionMode getExecutionMode() {

 			@Override
 			public ExecutableInvoker getExecutableInvoker() {
-				return null;
+				return new ExecutableInvoker() {
+					@Override
+					public Object invoke(Method method, Object target) {
+						return null;
+					}
+
+					@Override
+					public <T> T invoke(Constructor<T> constructor, Object outerInstance) {
+						return ReflectionUtils.newInstance(constructor);
+					}
+				};
 			}
 		};
 	}
@@ -334,7 +345,7 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
 	static class MissingNoArgumentsConstructorArgumentsProviderTestCase {

 		@ParameterizedTest
-		@ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class)
+		@ArgumentsSource(AmbiguousConstructorArgumentsProvider.class)
 		void method() {
 		}
 	}
@@ -342,7 +353,7 @@ void method() {
 	static class EmptyDisplayNameProviderTestCase {

 		@ParameterizedTest(name = "")
-		@ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class)
+		@ArgumentsSource(AmbiguousConstructorArgumentsProvider.class)
 		void method() {
 		}
 	}
@@ -350,14 +361,17 @@ void method() {
 	static class DefaultDisplayNameProviderTestCase {

 		@ParameterizedTest
-		@ArgumentsSource(MissingNoArgumentsConstructorArgumentsProvider.class)
+		@ArgumentsSource(AmbiguousConstructorArgumentsProvider.class)
 		void method() {
 		}
 	}

-	static class MissingNoArgumentsConstructorArgumentsProvider implements ArgumentsProvider {
+	static class AmbiguousConstructorArgumentsProvider implements ArgumentsProvider {
+
+		AmbiguousConstructorArgumentsProvider(String parameter) {
+		}

-		MissingNoArgumentsConstructorArgumentsProvider(String parameter) {
+		AmbiguousConstructorArgumentsProvider(int parameter) {
 		}

 		@Override
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java
index 9fdd334754ed..4ff8ba90e1e5 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java
@@ -42,6 +42,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -84,6 +85,8 @@
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.engine.JupiterTestEngine;
 import org.junit.jupiter.params.ParameterizedTestIntegrationTests.RepeatableSourcesTestCase.Action;
 import org.junit.jupiter.params.aggregator.AggregateWith;
@@ -1206,6 +1209,31 @@ void executesTwoIterationsBasedOnIterationAndUniqueIdSelector() {
 				.haveExactly(1, event(test(), displayName("[3] argument=5"), finishedWithFailure()));
 	}

+	@Nested
+	class SpiParameterInjectionIntegrationTests {
+
+		@Test
+		void injectsParametersIntoArgumentsProviderConstructor() {
+			execute(SpiParameterInjectionTestCase.class, "argumentsProviderWithConstructorParameter", String.class) //
+					.testEvents() //
+					.assertStatistics(it -> it.succeeded(1));
+		}
+
+		@Test
+		void injectsParametersIntoArgumentConverterConstructor() {
+			execute(SpiParameterInjectionTestCase.class, "argumentConverterWithConstructorParameter", String.class) //
+					.testEvents() //
+					.assertStatistics(it -> it.succeeded(1));
+		}
+
+		@Test
+		void injectsParametersIntoArgumentsAggregatorConstructor() {
+			execute(SpiParameterInjectionTestCase.class, "argumentsAggregatorWithConstructorParameter", String.class) //
+					.testEvents() //
+					.assertStatistics(it -> it.succeeded(1));
+		}
+	}
+
 	// -------------------------------------------------------------------------

 	static class TestCase {
@@ -1307,6 +1335,7 @@ void testWithThreeIterations(int argument) {
 		}
 	}

+	@SuppressWarnings("JUnitMalformedDeclaration")
 	static class NullSourceTestCase {

 		@ParameterizedTest
@@ -1342,6 +1371,7 @@ void testWithNullSourceForPrimitive(int argument) {

 	}

+	@SuppressWarnings("JUnitMalformedDeclaration")
 	static class EmptySourceTestCase {

 		@ParameterizedTest
@@ -1497,6 +1527,7 @@ void testWithEmptySourceForUnsupportedReferenceType(Integer argument) {

 	}

+	@SuppressWarnings("JUnitMalformedDeclaration")
 	static class NullAndEmptySourceTestCase {

 		@ParameterizedTest
@@ -1538,6 +1569,7 @@ void testWithNullAndEmptySourceForTwoDimensionalStringArray(String[][] argument)

 	}

+	@SuppressWarnings("JUnitMalformedDeclaration")
 	@TestMethodOrder(OrderAnnotation.class)
 	static class MethodSourceTestCase {

@@ -2119,6 +2151,71 @@ void testWithRepeatableArgumentsSource(String argument) {
 		}
 	}

+	static class SpiParameterInjectionTestCase {
+
+		@RegisterExtension
+		static final ParameterResolver spiParameterResolver = new ParameterResolver() {
+
+			@Override
+			public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
+					throws ParameterResolutionException {
+				return parameterContext.getDeclaringExecutable() instanceof Constructor //
+						&& String.class.equals(parameterContext.getParameter().getType());
+			}
+
+			@Override
+			public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
+					throws ParameterResolutionException {
+				return "resolved value";
+			}
+		};
+
+		@ParameterizedTest
+		@ArgumentsSource(ArgumentsProviderWithConstructorParameter.class)
+		void argumentsProviderWithConstructorParameter(String argument) {
+			assertEquals("resolved value", argument);
+		}
+
+		@ParameterizedTest
+		@ValueSource(strings = "value")
+		void argumentConverterWithConstructorParameter(
+				@ConvertWith(ArgumentConverterWithConstructorParameter.class) String argument) {
+			assertEquals("resolved value", argument);
+		}
+
+		@ParameterizedTest
+		@ValueSource(strings = "value")
+		void argumentsAggregatorWithConstructorParameter(
+				@AggregateWith(ArgumentsAggregatorWithConstructorParameter.class) String argument) {
+			assertEquals("resolved value", argument);
+		}
+
+		record ArgumentsProviderWithConstructorParameter(String value) implements ArgumentsProvider {
+
+			@Override
+			public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
+				return Stream.of(arguments(value));
+			}
+		}
+
+		record ArgumentConverterWithConstructorParameter(String value) implements ArgumentConverter {
+
+			@Override
+			public Object convert(Object source, ParameterContext context) throws ArgumentConversionException {
+				return value;
+			}
+		}
+
+		record ArgumentsAggregatorWithConstructorParameter(String value) implements ArgumentsAggregator {
+
+			@Override
+			public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context)
+					throws ArgumentsAggregationException {
+				return value;
+			}
+		}
+	}
+
 	private static class TwoSingleStringArgumentsProvider implements ArgumentsProvider {

 		@Override
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java
index 3bf17b6d5759..fd9e1d702c64 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestMethodContextTests.java
@@ -12,6 +12,7 @@

 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;

 import java.lang.reflect.Method;
 import java.util.Arrays;
@@ -33,13 +34,13 @@ class ParameterizedTestMethodContextTests {
 	@ValueSource(strings = { "onePrimitive", "twoPrimitives", "twoAggregators", "twoAggregatorsWithTestInfoAtTheEnd",
 			"mixedMode" })
 	void validSignatures(String name) {
-		assertTrue(new ParameterizedTestMethodContext(method(name)).hasPotentiallyValidSignature());
+		assertTrue(new ParameterizedTestMethodContext(method(name), mock()).hasPotentiallyValidSignature());
 	}

 	@ParameterizedTest
 	@ValueSource(strings = { "twoAggregatorsWithPrimitiveInTheMiddle", "twoAggregatorsWithTestInfoInTheMiddle" })
 	void invalidSignatures(String name) {
-		assertFalse(new ParameterizedTestMethodContext(method(name)).hasPotentiallyValidSignature());
+		assertFalse(new ParameterizedTestMethodContext(method(name), mock()).hasPotentiallyValidSignature());
 	}

 	private Method method(String name) {
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java
index a438edba25c2..9bd77fb62b74 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java
@@ -330,8 +330,8 @@ private static ParameterizedTestNameFormatter formatter(String pattern, String d
 	}

 	private static ParameterizedTestNameFormatter formatter(String pattern, String displayName, Method method) {
-		return new ParameterizedTestNameFormatter(pattern, displayName, new ParameterizedTestMethodContext(method),
-			512);
+		return new ParameterizedTestNameFormatter(pattern, displayName,
+			new ParameterizedTestMethodContext(method, mock()), 512);
 	}

 	private static String format(ParameterizedTestNameFormatter formatter, int invocationIndex, Arguments arguments) {


diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc
index c8ed02a67ceb..55fcc69e76fd 100644
--- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc
+++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc
@@ -16,7 +16,8 @@ on GitHub.
 [[release-notes-5.11.3-junit-platform-bug-fixes]]
 ==== Bug Fixes

-* ❓
+* Fixed a regression in method search algorithms introduced in 5.11.0 when classes reside
+  in the default package and using a Java 8 runtime.

 [[release-notes-5.11.3-junit-platform-deprecations-and-breaking-changes]]
 ==== Deprecations and Breaking Changes
diff --git a/junit-platform-commons/junit-platform-commons.gradle.kts b/junit-platform-commons/junit-platform-commons.gradle.kts
index c0d1404a6f60..ef52ce77ab56 100644
--- a/junit-platform-commons/junit-platform-commons.gradle.kts
+++ b/junit-platform-commons/junit-platform-commons.gradle.kts
@@ -29,6 +29,7 @@ tasks.jar {

 tasks.codeCoverageClassesJar {
 	exclude("org/junit/platform/commons/util/ModuleUtils.class")
+	exclude("org/junit/platform/commons/util/PackageNameUtils.class")
 }

 eclipse {
diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java
new file mode 100644
index 000000000000..9a018363a4a1
--- /dev/null
+++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/PackageNameUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015-2024 the original author or authors.
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * https://www.eclipse.org/legal/epl-v20.html
+ */
+
+package org.junit.platform.commons.util;
+
+import static org.junit.platform.commons.util.PackageUtils.DEFAULT_PACKAGE_NAME;
+
+/**
+ * Collection of utilities for working with package names.
+ *
+ *
DISCLAIMER

+ *
+ *
These utilities are intended solely for usage within the JUnit framework
+ * itself. Any usage by external parties is not supported.
+ * Use at your own risk!
+ *
+ * @since 1.11.3
+ */
+class PackageNameUtils {
+
+	static String getPackageName(Class<?> clazz) {
+		Package p = clazz.getPackage();
+		if (p != null) {
+			return p.getName();
+		}
+		String className = clazz.getName();
+		int index = className.lastIndexOf('.');
+		return index == -1 ? DEFAULT_PACKAGE_NAME : className.substring(0, index);
+	}
+
+}
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 26bd8e1698cf..77e270376854 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
@@ -19,6 +19,7 @@
 import static org.apiguardian.api.API.Status.INTERNAL;
 import static org.apiguardian.api.API.Status.STABLE;
 import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList;
+import static org.junit.platform.commons.util.PackageNameUtils.getPackageName;
 import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP;
 import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.TOP_DOWN;

@@ -1903,7 +1904,7 @@ private static boolean isPackagePrivate(Member member) {
 	}

 	private static boolean declaredInSamePackage(Method m1, Method m2) {
-		return m1.getDeclaringClass().getPackage().getName().equals(m2.getDeclaringClass().getPackage().getName());
+		return getPackageName(m1.getDeclaringClass()).equals(getPackageName(m2.getDeclaringClass()));
 	}

 	/**
diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java
new file mode 100644
index 000000000000..84afaf736290
--- /dev/null
+++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/PackageNameUtils.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015-2024 the original author or authors.
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * https://www.eclipse.org/legal/epl-v20.html
+ */
+
+package org.junit.platform.commons.util;
+
+/**
+ * Collection of utilities for working with package names.
+ *
+ *
DISCLAIMER

+ *
+ *
These utilities are intended solely for usage within the JUnit framework
+ * itself. Any usage by external parties is not supported.
+ * Use at your own risk!
+ *
+ * @since 1.11.3
+ */
+class PackageNameUtils {
+
+	static String getPackageName(Class<?> clazz) {
+		return clazz.getPackageName();
+	}
+
+}

Use the getPackageName utility function to safely compare package names of declaring classes.

Prompt:
The following is the text of a github issue and related comments for this repository:

Test discovery failing with NullPointerException when trying to find methods of a test class
## Context

We observe test discovery failing with a `NullPointerException` when trying to find test class methods (stacktrace is attached below). This seems to be a regression in 1.11.x version of `junit-platform-commons`. Discovery succeeds when using 1.10.x versions. Apparently, the `.getPackage()` in this method can yield `null`:
https://github.com/junit-team/junit5/blob/0de9d1033da1880dc61c72b02840941cfcc2d10e/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java#L1905-L1907

According to the [docs](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getPackage--) this can happen if the package object is not created by the classloader. I have not been able to create a standalone reproducer yet, but I'll keep trying :) So far, we've seen this happen only when running Spock 1.3 tests located in the root package.

### Stacktrace
```
Caused by: java.lang.NullPointerException
	at org.junit.platform.commons.util.ReflectionUtils.declaredInSamePackage(ReflectionUtils.java:1902)
	at org.junit.platform.commons.util.ReflectionUtils.isMethodOverriddenBy(ReflectionUtils.java:1888)
	at org.junit.platform.commons.util.ReflectionUtils.lambda$isMethodOverriddenByLocalMethods$35(ReflectionUtils.java:1870)
	at java.util.stream.MatchOps$1MatchSink.accept(MatchOps.java:90)
	at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1361)
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
	at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:516)
	at org.junit.platform.commons.util.ReflectionUtils.isMethodOverriddenByLocalMethods(ReflectionUtils.java:1870)
	at org.junit.platform.commons.util.ReflectionUtils.lambda$findAllMethodsInHierarchy$29(ReflectionUtils.java:1661)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
	at org.junit.platform.commons.util.ReflectionUtils.findAllMethodsInHierarchy(ReflectionUtils.java:1662)
	at org.junit.platform.commons.util.ReflectionUtils.streamMethods(ReflectionUtils.java:1642)
	at org.junit.platform.commons.util.ReflectionUtils.findMethods(ReflectionUtils.java:1627)
	at org.junit.platform.commons.util.ReflectionUtils.findMethods(ReflectionUtils.java:1618)
	at org.junit.vintage.engine.descriptor.TestSourceProvider.lambda$findMethod$1(TestSourceProvider.java:75)
	at java.util.HashMap.computeIfAbsent(HashMap.java:1128)
	at java.util.Collections$SynchronizedMap.computeIfAbsent(Collections.java:2674)
	at org.junit.vintage.engine.descriptor.TestSourceProvider.findMethod(TestSourceProvider.java:75)
	at org.junit.vintage.engine.descriptor.TestSourceProvider.computeTestSource(TestSourceProvider.java:56)
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
	at org.junit.vintage.engine.descriptor.TestSourceProvider.findTestSource(TestSourceProvider.java:47)
	at org.junit.vintage.engine.discovery.RunnerTestDescriptorPostProcessor.addChildrenRecursively(RunnerTestDescriptorPostProcessor.java:62)
	at org.junit.vintage.engine.discovery.RunnerTestDescriptorPostProcessor.applyFiltersAndCreateDescendants(RunnerTestDescriptorPostProcessor.java:41)
	at org.junit.vintage.engine.discovery.VintageDiscoverer.discover(VintageDiscoverer.java:46)
	at org.junit.vintage.engine.VintageTestEngine.discover(VintageTestEngine.java:64)
	at org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.discoverEngineRoot(EngineDiscoveryOrchestrator.java:152)
	... 13 more
```

I have a reproducer on Java 8 (probably related to JDK-8193889) when a class in the default package extends a class from a non-default package and both declare a package private method with the same signature.

Resolve the issue described above. Do not modify tests or user code. The issue can be resolved by modifying the actual library/application code. Make the minimal changes to resolve the issue while adhering to the specification and coding style of the codebase.

diff --git a/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java b/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java
new file mode 100644
index 000000000000..beebfdd5fd54
--- /dev/null
+++ b/platform-tooling-support-tests/projects/vintage/src/test/java/DefaultPackageTest.java
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright 2015-2024 the original author or authors.
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v2.0 which
+ * accompanies this distribution and is available at
+ *
+ * https://www.eclipse.org/legal/epl-v20.html
+ */
+import com.example.vintage.VintageTest;
+
+import org.junit.Ignore;
+
+/**
+ * Reproducer for https://github.com/junit-team/junit5/issues/4076
+ */
+@Ignore
+public class DefaultPackageTest extends VintageTest {
+	void packagePrivateMethod() {
+	}
+}
diff --git a/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java b/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java
index 1632b1e3537b..a6efb8990791 100644
--- a/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java
+++ b/platform-tooling-support-tests/projects/vintage/src/test/java/com/example/vintage/VintageTest.java
@@ -15,6 +15,9 @@
 import org.junit.Test;

 public class VintageTest {
+	void packagePrivateMethod() {
+	}
+
 	@Test
 	public void success() {
 		// pass


diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp
index 4447091347..106c23fb2e 100644
--- a/include/nlohmann/detail/iterators/iter_impl.hpp
+++ b/include/nlohmann/detail/iterators/iter_impl.hpp
@@ -474,7 +474,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
        if (m_object == nullptr)
        {
@@ -519,7 +523,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
        if (m_object == nullptr)
        {

diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 152a4514b9..4ba491a831 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -35,28 +35,29 @@ jobs:
 #      - name: Test
 #        run: cd build ; ctest -j 10 --output-on-failure

-  macos-12:
-    runs-on: macos-12 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md
-    strategy:
-      matrix:
-        xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1']
-    env:
-      DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
-
-    steps:
-      - uses: actions/checkout@v4
-      - name: Run CMake
-        run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON
-      - name: Build
-        run: cmake --build build --parallel 10
-      - name: Test
-        run: cd build ; ctest -j 10 --output-on-failure
+# macos-12 is deprecated (https://github.com/actions/runner-images/issues/10721)
+#  macos-12:
+#    runs-on: macos-12 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md
+#    strategy:
+#      matrix:
+#        xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1']
+#    env:
+#      DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
+#
+#    steps:
+#      - uses: actions/checkout@v4
+#      - name: Run CMake
+#        run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON
+#      - name: Build
+#        run: cmake --build build --parallel 10
+#      - name: Test
+#        run: cd build ; ctest -j 10 --output-on-failure

   macos-13:
     runs-on: macos-13 # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md
     strategy:
       matrix:
-        xcode: [ '14.2', '14.3', '14.3.1', '15.0.1', '15.1', '15.2']
+        xcode: ['14.1', '14.2', '14.3', '14.3.1', '15.0.1', '15.1', '15.2']
     env:
       DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer

diff --git a/README.md b/README.md
index 34a79f400e..a493092827 100644
--- a/README.md
+++ b/README.md
@@ -1115,7 +1115,7 @@ Though it's 2024 already, the support for C++11 is still a bit sparse. Currently

 - GCC 4.8 - 14.2 (and possibly later)
 - Clang 3.4 - 20.0 (and possibly later)
-- Apple Clang 9.1 - 16.0 (and possibly later)
+- Apple Clang 9.1 - 16.1 (and possibly later)
 - Intel C++ Compiler 17.0.2 (and possibly later)
 - Nvidia CUDA Compiler 11.0.221 (and possibly later)
 - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
@@ -1146,13 +1146,7 @@ The following compilers are currently used in continuous integration at [AppVeyo

 | Compiler                                                                                | Operating System   | CI Provider    |
 |--------------------------------------------------------------------------------------------------------|--------------------|----------------|
-| Apple Clang 13.0.0 (clang-1300.0.29.3);   Xcode 13.1                                                   | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 13.0.0 (clang-1300.0.29.30);  Xcode 13.2.1                                                 | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 13.1.6 (clang-1316.0.21.2.3); Xcode 13.3.1                                                 | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 13.1.6 (clang-1316.0.21.2.5); Xcode 13.4.1                                                 | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0                                                   | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0.1                                                 | macOS 12.7.6       | GitHub Actions |
-| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1                                                   | macOS 12.7.6       | GitHub Actions |
+| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1                                                   | macOS 13.7         | GitHub Actions |
 | Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.2                                                   | macOS 13.7         | GitHub Actions |
 | Apple Clang 14.0.3 (clang-1403.0.22.14.1); Xcode 14.3                                                  | macOS 13.7         | GitHub Actions |
 | Apple Clang 14.0.3 (clang-1403.0.22.14.1); Xcode 14.3.1                                                | macOS 13.7.1       | GitHub Actions |
diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp
index 4447091347..106c23fb2e 100644
--- a/include/nlohmann/detail/iterators/iter_impl.hpp
+++ b/include/nlohmann/detail/iterators/iter_impl.hpp
@@ -463,7 +463,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
     bool operator==(const IterImpl& other) const
@@ -474,7 +474,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            return true;
+        }

         switch (m_object->m_data.m_type)
         {
@@ -499,7 +503,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: not equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
     bool operator!=(const IterImpl& other) const
@@ -509,7 +513,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: smaller
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator<(const iter_impl& other) const
     {
@@ -519,7 +523,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false
+            return false;
+        }

         switch (m_object->m_data.m_type)
         {
@@ -544,7 +553,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: less than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator<=(const iter_impl& other) const
     {
@@ -553,7 +562,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: greater than
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator>(const iter_impl& other) const
     {
@@ -562,7 +571,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: greater than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized.
     */
     bool operator>=(const iter_impl& other) const
     {
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index a6b4c3a713..09fffb3bd1 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -13439,7 +13439,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
     bool operator==(const IterImpl& other) const
@@ -13450,7 +13450,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            return true;
+        }

         switch (m_object->m_data.m_type)
         {
@@ -13475,7 +13479,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: not equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
     bool operator!=(const IterImpl& other) const
@@ -13485,7 +13489,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: smaller
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator<(const iter_impl& other) const
     {
@@ -13495,7 +13499,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false
+            return false;
+        }

         switch (m_object->m_data.m_type)
         {
@@ -13520,7 +13529,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: less than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator<=(const iter_impl& other) const
     {
@@ -13529,7 +13538,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: greater than
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.
     */
     bool operator>(const iter_impl& other) const
     {
@@ -13538,7 +13547,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci

     /*!
     @brief comparison: greater than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized.
     */
     bool operator>=(const iter_impl& other) const
     {

Handle default-initialized iterators by considering them equal: if both iterators have `m_object == nullptr`, return `true` for equality and `false` for less-than comparison.

Prompt:
The following is the text of a github issue and related comments for this repository:

Default initialized iterators are not comparable
### Description

I have a use-case where I iterate over collections in a generic manner (using templates). However, iteration over basic_json fails due to the statement:
```
        JSON_ASSERT(m_object != nullptr);
```

Before asserting for non-null object, shouldn't we first check of `other.m_object` is null too? If both are null, the operator should return true before the assertion.

### Reproduction steps

`nlohmann::json::iterator{} == nlohmann::json::iterator{}`

### Expected vs. actual results

Expected: Should return true of m_object is nullptr for both objects

Actual: Assertion fails

Similar behavior should happen for other comparison methods.

### Minimal code example

_No response_

### Error messages

_No response_

### Compiler and operating system

gcc 9.3

### Library version

3.11.3

### Validation

- [X] The bug also occurs if the latest version from the [`develop`](https://github.com/nlohmann/json/tree/develop) branch is used.
- [X] I can successfully [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests).

Resolve the issue described above. Do not modify tests or user code. The issue can be resolved by modifying the actual library/application code. Make the minimal changes to resolve the issue while adhering to the specification and coding style of the codebase.

diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp
index 4447091347..106c23fb2e 100644
--- a/include/nlohmann/detail/iterators/iter_impl.hpp
+++ b/include/nlohmann/detail/iterators/iter_impl.hpp
@@ -474,7 +474,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            return true;
+        }

         switch (m_object->m_data.m_type)
         {
@@ -519,7 +523,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
         }

-        JSON_ASSERT(m_object != nullptr);
+        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
+        if (m_object == nullptr)
+        {
+            // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false
+            return false;
+        }

         switch (m_object->m_data.m_type)
         {

diff --git a/tests/src/unit-iterators3.cpp b/tests/src/unit-iterators3.cpp
new file mode 100644
index 0000000000..4b5cff7e21
--- /dev/null
+++ b/tests/src/unit-iterators3.cpp
@@ -0,0 +1,35 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
+// |  |  |__   |  |  | | | |  version 3.11.3
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#include "doctest_compatibility.h"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <nlohmann/json.hpp>
+using nlohmann::json;
+
+#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
+    #define JSON_HAS_CPP_14
+#endif
+
+#ifdef JSON_HAS_CPP_14
+TEST_CASE_TEMPLATE("checking forward-iterators", T, // NOLINT(readability-math-missing-parentheses)
+                   std::vector<int>, std::string, nlohmann::json)
+{
+    auto it1 = typename T::iterator{};
+    auto it2 = typename T::iterator{};
+    CHECK(it1 == it2);
+    CHECK(it1 <= it2);
+    CHECK(it1 >= it2);
+    CHECK_FALSE(it1 != it2);
+    CHECK_FALSE(it1 < it2);
+    CHECK_FALSE(it1 > it2);
+}
+#endif


diff --git a/docs/mkdocs/docs/api/basic_json/get_ptr.md b/docs/mkdocs/docs/api/basic_json/get_ptr.md
index 2441e1156e..b1ecf44d82 100644
--- a/docs/mkdocs/docs/api/basic_json/get_ptr.md
+++ b/docs/mkdocs/docs/api/basic_json/get_ptr.md
@@ -35,7 +35,35 @@ Constant.

 !!! danger "Undefined behavior"

-    Writing data to the pointee of the result yields an undefined state.
+    The pointer becomes invalid if the underlying JSON object changes.
+
+    Consider the following example code where the pointer `ptr` changes after the array is resized. As a result, reading or writing to `ptr` after the array change would be undefined behavior. The address of the first array element changes, because the underlying `std::vector` is resized after adding a fifth element.
+
+    ```cpp
+    #include <iostream>
+    #include <nlohmann/json.hpp>
+
+    using json = nlohmann::json;
+
+    int main()
+    {
+        json j = {1, 2, 3, 4};
+        auto* ptr = j[0].get_ptr<std::int64_t*>();
+        std::cout << "value at " << ptr << " is " << *ptr << std::endl;
+
+        j.push_back(5);
+
+        ptr = j[0].get_ptr<std::int64_t*>();
+        std::cout << "value at " << ptr << " is " << *ptr << std::endl;
+    }
+    ```
+
+    Output:
+
+    ```
+    value at 0x6000012fc1c8 is 1
+    value at 0x6000029fc088 is 1
+    ```

 ## Examples

@@ -54,6 +82,10 @@ Constant.
     --8<-- "examples/get_ptr.output"
     ```

+## See also
+
+- [get_ref()](get_ref.md) get a reference value
+
 ## Version history

 - Added in version 1.0.0.
diff --git a/docs/mkdocs/docs/api/basic_json/get_ref.md b/docs/mkdocs/docs/api/basic_json/get_ref.md
index b1219742ca..73b20b0e08 100644
--- a/docs/mkdocs/docs/api/basic_json/get_ref.md
+++ b/docs/mkdocs/docs/api/basic_json/get_ref.md
@@ -40,7 +40,7 @@ Constant.

 !!! danger "Undefined behavior"

-    Writing data to the referee of the result yields an undefined state.
+    The reference becomes invalid if the underlying JSON object changes.

 ## Examples

@@ -58,6 +58,10 @@ Constant.
     --8<-- "examples/get_ref.output"
     ```

+## See also
+
+- [get_ptr()](get_ptr.md) get a pointer value
+
 ## Version history

 - Added in version 1.1.0.
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index e004e83082..763fd95783 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -1463,13 +1463,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
     /// get a pointer to the value (integer number)
     number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
     {
-        return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
+        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
     }

     /// get a pointer to the value (integer number)
     constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
     {
-        return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
+        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
     }

     /// get a pointer to the value (unsigned number)
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 02441416bf..86d1cd3e88 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -20962,13 +20962,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
     /// get a pointer to the value (integer number)
     number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
     {
-        return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
+        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
     }

     /// get a pointer to the value (integer number)
     constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
     {
-        return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
+        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
     }

     /// get a pointer to the value (unsigned number)

Check specifically for signed integer type instead of using the more general number check when getting a pointer to an integer value.

Prompt:
The following is the text of a github issue and related comments for this repository:

Invalid union access for get_ref/get_ptr with unsigned integer
### Description

When a JSON value is stored as unsigned integer, it is possible to call `get_ref<number_integer_t>()` or `get_ptr<number_integer_t>()` without error, which accesses the *signed* integer member of the internal union instead of the *unsigned* member. This is undefined behaviour in C++ standard and should not be allowed (especially since trying access with other more clearly incompatible types, such as strings, is already checked and reported as an error).

The root of the problem is that `is_number_integer()` returns `true` for both signed and unsigned integer storage, yet is used to guard reference/pointer access using signed integers: https://github.com/nlohmann/json/blob/63258397761b3dd96dd171e5a5ad5aa915834c35/include/nlohmann/json.hpp#L1464-L1467

I also note [the docs](https://json.nlohmann.me/api/basic_json/get_ref/#notes) say that "Writing data to the referee of the result yields an undefined state.", which isn't very clear. Does this mean we are not supposed to write a value to the object pointed to by the reference/pointer? The earlier wording (changed in https://github.com/nlohmann/json/commit/4e52277b70999ccf8858c7995dd72808a7e82c33#diff-b56a00981d8f3b87e3ce49a7eb27d36f4586d9c54c3fb628a88cfc000aa5fed4L2632) was "The pointer becomes invalid if the underlying JSON object changes.", which made more sense.

### Reproduction steps

See code example below.

### Expected vs. actual results

Expected: type error exception.
Actual: no error, unsigned data is access as signed data (undefined behaviour).

### Minimal code example

```c++
#include <nlohmann/json.hpp>
#include <iostream>

int main() {
    using namespace nlohmann;

    json j = json::number_unsigned_t{1u};
    assert(j.is_number_unsigned());

    j.get_ref<json::number_integer_t&>() = -1;
    assert(j.is_number_unsigned());

    std::cout << j.get<json::number_unsigned_t>() << std::endl;
    return 0;
}
```

### Error messages

```Shell
None.
```

### Compiler and operating system

Linux x64, gcc 11

### Library version

3.11.3

### Validation

- [X] The bug also occurs if the latest version from the [`develop`](https://github.com/nlohmann/json/tree/develop) branch is used.
- [X] I can successfully [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests).

Resolve the issue described above. Do not modify tests or user code. The issue can be resolved by modifying the actual library/application code. Make the minimal changes to resolve the issue while adhering to the specification and coding style of the codebase.

diff --git a/tests/src/unit-pointer_access.cpp b/tests/src/unit-pointer_access.cpp
index 6b1a6f8a83..b5734559bc 100644
--- a/tests/src/unit-pointer_access.cpp
+++ b/tests/src/unit-pointer_access.cpp
@@ -326,7 +326,7 @@ TEST_CASE("pointer access")
         CHECK(value.get_ptr<json::array_t*>() == nullptr);
         CHECK(value.get_ptr<json::string_t*>() == nullptr);
         CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
-        CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
+        CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
         CHECK(value.get_ptr<json::number_unsigned_t*>() != nullptr);
         CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
         CHECK(value.get_ptr<json::binary_t*>() == nullptr);
@@ -355,7 +355,7 @@ TEST_CASE("pointer access")
         CHECK(value.get_ptr<const json::array_t*>() == nullptr);
         CHECK(value.get_ptr<const json::string_t*>() == nullptr);
         CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
-        CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
+        CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
         CHECK(value.get_ptr<const json::number_unsigned_t*>() != nullptr);
         CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
         CHECK(value.get_ptr<const json::binary_t*>() == nullptr);
diff --git a/tests/src/unit-reference_access.cpp b/tests/src/unit-reference_access.cpp
index e4cc2d5b2a..d63a470de0 100644
--- a/tests/src/unit-reference_access.cpp
+++ b/tests/src/unit-reference_access.cpp
@@ -215,8 +215,8 @@ TEST_CASE("reference access")
                              "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
         CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
                              "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
-        //CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
-        //    "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
+        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
+                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
         CHECK_NOTHROW(value.get_ref<json::number_unsigned_t&>());
         CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
     }