Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ tasks.withType<JavaCompile>().configureEach {
disableAllChecks = true
nullaway {
enable()
isJSpecifyMode = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public interface InvocationInterceptor extends TestInstantiationAwareExtension {
* @return the result of the invocation; never {@code null}
* @throws Throwable in case of failure
*/
default <T> T interceptTestClassConstructor(Invocation<T> invocation,
default <T> @Nullable T interceptTestClassConstructor(Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext, ExtensionContext extensionContext)
throws Throwable {
return invocation.proceed();
Expand All @@ -94,7 +94,7 @@ default <T> T interceptTestClassConstructor(Invocation<T> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptBeforeAllMethod(Invocation<@Nullable Void> invocation,
default void interceptBeforeAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}
Expand All @@ -109,7 +109,7 @@ default void interceptBeforeAllMethod(Invocation<@Nullable Void> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptBeforeEachMethod(Invocation<@Nullable Void> invocation,
default void interceptBeforeEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}
Expand All @@ -124,8 +124,8 @@ default void interceptBeforeEachMethod(Invocation<@Nullable Void> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptTestMethod(Invocation<@Nullable Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
default void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}

Expand All @@ -143,7 +143,7 @@ default void interceptTestMethod(Invocation<@Nullable Void> invocation,
* @return the result of the invocation; potentially {@code null}
* @throws Throwable in case of failures
*/
default <T extends @Nullable Object> T interceptTestFactoryMethod(Invocation<T> invocation,
default <T> @Nullable T interceptTestFactoryMethod(Invocation<T> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
return invocation.proceed();
}
Expand All @@ -158,7 +158,7 @@ default void interceptTestMethod(Invocation<@Nullable Void> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptTestTemplateMethod(Invocation<@Nullable Void> invocation,
default void interceptTestTemplateMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}
Expand All @@ -174,8 +174,8 @@ default void interceptTestTemplateMethod(Invocation<@Nullable Void> invocation,
* @throws Throwable in case of failures
*/
@API(status = STABLE, since = "5.11")
default void interceptDynamicTest(Invocation<@Nullable Void> invocation,
DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
default void interceptDynamicTest(Invocation<Void> invocation, DynamicTestInvocationContext invocationContext,
ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}

Expand All @@ -189,7 +189,7 @@ default void interceptDynamicTest(Invocation<@Nullable Void> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptAfterEachMethod(Invocation<@Nullable Void> invocation,
default void interceptAfterEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}
Expand All @@ -204,7 +204,7 @@ default void interceptAfterEachMethod(Invocation<@Nullable Void> invocation,
* @param extensionContext the current extension context; never {@code null}
* @throws Throwable in case of failures
*/
default void interceptAfterAllMethod(Invocation<@Nullable Void> invocation,
default void interceptAfterAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
invocation.proceed();
}
Expand All @@ -218,14 +218,15 @@ default void interceptAfterAllMethod(Invocation<@Nullable Void> invocation,
* @since 5.5
*/
@API(status = STABLE, since = "5.10")
interface Invocation<T extends @Nullable Object> {
interface Invocation<T> {

/**
* Proceed with this invocation.
*
* @return the result of this invocation; potentially {@code null}.
* @throws Throwable in case the invocation failed
*/
@Nullable
T proceed() throws Throwable;
Comment on lines +229 to 230
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really make sense to force all Invocation implementations to return @Nullable value?
Would it be better to keep an older Invocation<T extends @Nullable Object> approach so every implementation declares if it really wants to produce nullable value or not?


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ private Object invokeTestClassConstructor(Optional<Object> outerInstance, Extens
ExtensionContextSupplier extensionContext) {

Constructor<?> constructor = ReflectionUtils.getDeclaredConstructor(getTestClass());
return executableInvoker.invoke(constructor, outerInstance, extensionContext, registry,
InvocationInterceptor::interceptTestClassConstructor);
return requireNonNull(executableInvoker.invoke(constructor, outerInstance, extensionContext, registry,
InvocationInterceptor::interceptTestClassConstructor));
}

private void invokeTestInstancePreConstructCallbacks(TestInstanceFactoryContext factoryContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext conte
return context;
}

@SuppressWarnings("NullAway")
private InvocationInterceptor.Invocation<Void> toInvocation() {
return () -> {
requiredDynamicTest().getExecutable().execute();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class TestFactoryTestDescriptor extends TestMethodTestDescriptor implemen
public static final String DYNAMIC_TEST_SEGMENT_TYPE = "dynamic-test";

@SuppressWarnings("NullAway")
private static final ReflectiveInterceptorCall<Method, @Nullable Object> interceptorCall = InvocationInterceptor::interceptTestFactoryMethod;
private static final ReflectiveInterceptorCall<Method, Object> interceptorCall = InvocationInterceptor::interceptTestFactoryMethod;
private static final InterceptingExecutableInvoker executableInvoker = new InterceptingExecutableInvoker();

private final DynamicDescendantFilter dynamicDescendantFilter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ public class InterceptingExecutableInvoker {
* invocation via all registered {@linkplain InvocationInterceptor
* interceptors}
*/
public <T> T invoke(Constructor<T> constructor, Optional<Object> outerInstance,
public <T> @Nullable T invoke(Constructor<T> constructor, Optional<Object> outerInstance,
ExtensionContextSupplier extensionContext, ExtensionRegistry extensionRegistry,
ReflectiveInterceptorCall<Constructor<T>, T> interceptorCall) {

@Nullable
Object[] arguments = resolveParameters(constructor, Optional.empty(), outerInstance, extensionContext,
extensionRegistry);
ConstructorInvocation<T> invocation = new ConstructorInvocation<>(constructor, arguments);
ConstructorInvocation<T> invocation = newConstructorInvocation(constructor, arguments);
return invoke(invocation, invocation, extensionContext, extensionRegistry, interceptorCall);
}

Expand All @@ -78,40 +78,53 @@ public <T> T invoke(Constructor<T> constructor, Optional<Object> outerInstance,
* @param interceptorCall the call for intercepting this method invocation
* via all registered {@linkplain InvocationInterceptor interceptors}
*/
public <T> T invoke(Method method, @Nullable Object target, ExtensionContext extensionContext,
public <T> @Nullable T invoke(Method method, @Nullable Object target, ExtensionContext extensionContext,
ExtensionRegistry extensionRegistry, ReflectiveInterceptorCall<Method, T> interceptorCall) {

@SuppressWarnings({ "unchecked", "rawtypes" })
Optional<Object> optionalTarget = (target instanceof Optional optional ? optional
: Optional.ofNullable(target));
@Nullable
Object[] arguments = resolveParameters(method, optionalTarget, extensionContext, extensionRegistry);
MethodInvocation<T> invocation = new MethodInvocation<>(method, optionalTarget, arguments);
MethodInvocation<T> invocation = newMethodInvocation(method, optionalTarget, arguments);
return invoke(invocation, invocation, extensionContext, extensionRegistry, interceptorCall);
}

private <E extends Executable, T> T invoke(Invocation<T> originalInvocation,
private <E extends Executable, T extends @Nullable Object> @Nullable T invoke(Invocation<T> originalInvocation,
ReflectiveInvocationContext<E> invocationContext, ExtensionContext extensionContext,
ExtensionRegistry extensionRegistry, ReflectiveInterceptorCall<E, T> call) {
return interceptorChain.invoke(originalInvocation, extensionRegistry, (interceptor,
wrappedInvocation) -> call.apply(interceptor, wrappedInvocation, invocationContext, extensionContext));
}

private <E extends Executable, T> T invoke(Invocation<T> originalInvocation,
private <E extends Executable, T> @Nullable T invoke(Invocation<T> originalInvocation,
ReflectiveInvocationContext<E> invocationContext, ExtensionContextSupplier extensionContext,
ExtensionRegistry extensionRegistry, ReflectiveInterceptorCall<E, T> call) {
return interceptorChain.invoke(originalInvocation, extensionRegistry,
(interceptor, wrappedInvocation) -> call.apply(interceptor, wrappedInvocation, invocationContext,
extensionContext.get(interceptor)));
}

public interface ReflectiveInterceptorCall<E extends Executable, T extends @Nullable Object> {
@SuppressWarnings("NullAway")
private static <T> ConstructorInvocation<T> newConstructorInvocation(Constructor<T> constructor,
@Nullable Object[] arguments) {
return new ConstructorInvocation<>(constructor, arguments);
}

@SuppressWarnings("NullAway")
private static <T> MethodInvocation<T> newMethodInvocation(Method method, Optional<Object> optionalTarget,
@Nullable Object[] arguments) {
return new MethodInvocation<>(method, optionalTarget, arguments);
}

public interface ReflectiveInterceptorCall<E extends Executable, T> {

@Nullable
T apply(InvocationInterceptor interceptor, Invocation<T> invocation,
ReflectiveInvocationContext<E> invocationContext, ExtensionContext extensionContext) throws Throwable;

@SuppressWarnings("NullAway")
static ReflectiveInterceptorCall<Method, @Nullable Void> ofVoidMethod(VoidMethodInterceptorCall call) {
static ReflectiveInterceptorCall<Method, Void> ofVoidMethod(VoidMethodInterceptorCall call) {
return ((interceptorChain, invocation, invocationContext, extensionContext) -> {
call.apply(interceptorChain, invocation, invocationContext, extensionContext);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@
@API(status = INTERNAL, since = "5.5")
public class InvocationInterceptorChain {

public <T> T invoke(Invocation<T> invocation, ExtensionRegistry extensionRegistry, InterceptorCall<T> call) {
public <T> @Nullable T invoke(Invocation<T> invocation, ExtensionRegistry extensionRegistry,
InterceptorCall<T> call) {
List<InvocationInterceptor> interceptors = extensionRegistry.getExtensions(InvocationInterceptor.class);
if (interceptors.isEmpty()) {
return proceed(invocation);
}
return chainAndInvoke(invocation, call, interceptors);
}

private <T> T chainAndInvoke(Invocation<T> invocation, InterceptorCall<T> call,
private <T> @Nullable T chainAndInvoke(Invocation<T> invocation, InterceptorCall<T> call,
List<InvocationInterceptor> interceptors) {

ValidatingInvocation<T> validatingInvocation = new ValidatingInvocation<>(invocation, interceptors);
Expand All @@ -60,7 +61,7 @@ private <T> Invocation<T> chainInterceptors(Invocation<T> invocation, Intercepto
return result;
}

private <T> T proceed(Invocation<T> invocation) {
private <T> @Nullable T proceed(Invocation<T> invocation) {
try {
return invocation.proceed();
}
Expand All @@ -70,12 +71,13 @@ private <T> T proceed(Invocation<T> invocation) {
}

@FunctionalInterface
public interface InterceptorCall<T extends @Nullable Object> {
public interface InterceptorCall<T> {

@Nullable
T apply(InvocationInterceptor interceptor, Invocation<T> invocation) throws Throwable;

@SuppressWarnings("NullAway")
static InterceptorCall<@Nullable Void> ofVoid(VoidInterceptorCall call) {
static InterceptorCall<Void> ofVoid(VoidInterceptorCall call) {
return ((interceptorChain, invocation) -> {
call.apply(interceptorChain, invocation);
return null;
Expand All @@ -87,15 +89,15 @@ public interface InterceptorCall<T extends @Nullable Object> {
@FunctionalInterface
public interface VoidInterceptorCall {

void apply(InvocationInterceptor interceptor, Invocation<@Nullable Void> invocation) throws Throwable;
void apply(InvocationInterceptor interceptor, Invocation<Void> invocation) throws Throwable;

}

private record InterceptedInvocation<T>(Invocation<T> invocation, InterceptorCall<T> call,
InvocationInterceptor interceptor) implements Invocation<T> {

@Override
public T proceed() throws Throwable {
public @Nullable T proceed() throws Throwable {
return call.apply(interceptor, invocation);
}

Expand All @@ -119,7 +121,7 @@ private static class ValidatingInvocation<T extends @Nullable Object> implements
}

@Override
public T proceed() throws Throwable {
public @Nullable T proceed() throws Throwable {
markInvokedOrSkipped();
return delegate.proceed();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,30 @@ public NamespaceAwareStore(NamespacedHierarchicalStore<Namespace> valuesStore, N
}

@Override
@SuppressWarnings("NullAway")
public @Nullable Object get(Object key) {
Preconditions.notNull(key, "key must not be null");
return accessStore(() -> this.valuesStore.get(this.namespace, key));
}

@Override
@SuppressWarnings("NullAway")
public <T> @Nullable T get(Object key, Class<T> requiredType) {
Preconditions.notNull(key, "key must not be null");
Preconditions.notNull(requiredType, "requiredType must not be null");
return accessStore(() -> this.valuesStore.get(this.namespace, key, requiredType));
}

@Override
@SuppressWarnings("NullAway")
public <K, V> @Nullable Object getOrComputeIfAbsent(K key, Function<K, V> defaultCreator) {
Preconditions.notNull(key, "key must not be null");
Preconditions.notNull(defaultCreator, "defaultCreator function must not be null");
return accessStore(() -> this.valuesStore.getOrComputeIfAbsent(this.namespace, key, defaultCreator));
}

@Override
@SuppressWarnings("NullAway")
public <K, V> @Nullable V getOrComputeIfAbsent(K key, Function<K, V> defaultCreator, Class<V> requiredType) {
Preconditions.notNull(key, "key must not be null");
Preconditions.notNull(defaultCreator, "defaultCreator function must not be null");
Expand All @@ -68,18 +72,21 @@ public NamespaceAwareStore(NamespacedHierarchicalStore<Namespace> valuesStore, N
}

@Override
@SuppressWarnings("NullAway")
public void put(Object key, @Nullable Object value) {
Preconditions.notNull(key, "key must not be null");
accessStore(() -> this.valuesStore.put(this.namespace, key, value));
}

@Override
@SuppressWarnings("NullAway")
public @Nullable Object remove(Object key) {
Preconditions.notNull(key, "key must not be null");
return accessStore(() -> this.valuesStore.remove(this.namespace, key));
}

@Override
@SuppressWarnings("NullAway")
public <T> @Nullable T remove(Object key, Class<T> requiredType) {
Preconditions.notNull(key, "key must not be null");
Preconditions.notNull(requiredType, "requiredType must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SeparateThreadTimeoutInvocation<T extends @Nullable Object> implements Inv
}

@Override
@SuppressWarnings("NullAway")
public T proceed() throws Throwable {
return assertTimeoutPreemptively(timeout.toDuration(), delegate::proceed, descriptionSupplier,
(__, messageSupplier, cause, testThread) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void interceptTestTemplateMethod(Invocation<Void> invocation,
}

@Override
public <T> T interceptTestFactoryMethod(Invocation<T> invocation,
public <T> @Nullable T interceptTestFactoryMethod(Invocation<T> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {

return interceptTestableMethod(invocation, invocationContext, extensionContext,
Expand Down Expand Up @@ -145,7 +145,7 @@ private Optional<ThreadMode> readTimeoutThreadModeFromAnnotation(Optional<Annota
return AnnotationSupport.findAnnotation(element, Timeout.class).map(Timeout::threadMode);
}

private <T> T interceptTestableMethod(Invocation<T> invocation,
private <T> @Nullable T interceptTestableMethod(Invocation<T> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext,
TimeoutProvider defaultTimeoutProvider) throws Throwable {

Expand All @@ -154,7 +154,7 @@ private <T> T interceptTestableMethod(Invocation<T> invocation,
return intercept(invocation, invocationContext, extensionContext, timeout, defaultTimeoutProvider);
}

private <T> T intercept(Invocation<T> invocation, ReflectiveInvocationContext<Method> invocationContext,
private <T> @Nullable T intercept(Invocation<T> invocation, ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext, @Nullable TimeoutDuration explicitTimeout,
TimeoutProvider defaultTimeoutProvider) throws Throwable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static Type getGenericReturnType(Method method) {
: method.getGenericReturnType();
}

@SuppressWarnings("NullAway")
public static @Nullable Object invoke(Method method, @Nullable Object target, @Nullable Object[] arguments) {
if (isKotlinSuspendingFunction(method)) {
return invokeKotlinSuspendingFunction(method, target, arguments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Concurrent implements ResolutionCache {
private final Map<ParameterDeclaration, Object> cache = new ConcurrentHashMap<>();

@Override
public Object resolve(ParameterDeclaration declaration, Supplier<Object> resolver) {
public @Nullable Object resolve(ParameterDeclaration declaration, Supplier<@Nullable Object> resolver) {
return cache.computeIfAbsent(declaration, __ -> resolver.get());
}
}
Expand Down
Loading
Loading