GH-1192 - Migrate code base to jSpecify for nullness verification.
This commit is contained in:
@@ -17,6 +17,11 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-modulith-core</artifactId>
|
||||
@@ -67,4 +72,5 @@
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.data.domain.DomainEvents;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
@@ -67,7 +68,7 @@ public class AggregateTestUtils {
|
||||
*/
|
||||
private static class DomainEventsMethodFinder implements MethodCallback {
|
||||
|
||||
Method method;
|
||||
@Nullable Method method;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
@@ -145,7 +146,7 @@ class DefaultPublishedEvents implements PublishedEvents, ApplicationListener<App
|
||||
* @see org.springframework.modulith.test.PublishedEvents.TypedPublishedEvents#matching(java.util.function.Function, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <S> TypedPublishedEvents<T> matching(Function<T, S> mapper, S value) {
|
||||
public <S> TypedPublishedEvents<T> matching(Function<T, S> mapper, @Nullable S value) {
|
||||
return matching(mapper, (Predicate<S>) it -> Objects.equals(it, value));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -50,7 +51,7 @@ class ModuleContextCustomizerFactory implements ContextCustomizerFactory {
|
||||
* @see org.springframework.test.context.ContextCustomizerFactory#createContextCustomizer(java.lang.Class, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public ContextCustomizer createContextCustomizer(Class<?> testClass,
|
||||
public @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,
|
||||
List<ContextConfigurationAttributes> configAttributes) {
|
||||
|
||||
var moduleTest = TestContextAnnotationUtils.findAnnotationDescriptor(testClass, ApplicationModuleTest.class);
|
||||
@@ -239,6 +240,11 @@ class ModuleContextCustomizerFactory implements ContextCustomizerFactory {
|
||||
for (String name : registry.getBeanDefinitionNames()) {
|
||||
|
||||
var type = factory.getType(name, false);
|
||||
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var module = modules.getModuleByType(type)
|
||||
.filter(Predicate.not(ApplicationModule::isRootModule));
|
||||
|
||||
|
||||
@@ -109,15 +109,21 @@ public class ModuleTestExecution implements Iterable<ApplicationModule> {
|
||||
return () -> {
|
||||
|
||||
var annotation = AnnotatedElementUtils.findMergedAnnotation(type, ApplicationModuleTest.class);
|
||||
var packageName = type.getPackage().getName();
|
||||
|
||||
if (annotation == null) {
|
||||
throw new IllegalStateException(
|
||||
"%s not found on %s!".formatted(ApplicationModuleTest.class.getName(), type.getName()));
|
||||
}
|
||||
|
||||
var packageName = PackageName.ofType(type).toString();
|
||||
var modules = BOOTSTRAP.of(findSpringBootApplicationByClasses(annotation, type));
|
||||
var moduleName = annotation.module();
|
||||
|
||||
var module = StringUtils.hasText(moduleName)
|
||||
? modules.getModuleByName(moduleName).orElseThrow( //
|
||||
() -> new IllegalStateException(String.format("Unable to find module %s!", moduleName)))
|
||||
() -> new IllegalStateException("Unable to find module %s!".formatted(moduleName)))
|
||||
: modules.getModuleForPackage(packageName).orElseThrow( //
|
||||
() -> new IllegalStateException(String.format("Package %s is not part of any module!", packageName)));
|
||||
() -> new IllegalStateException("Package %s is not part of any module!".formatted(packageName)));
|
||||
|
||||
return EXECUTIONS.computeIfAbsent(new Key(module.getBasePackage().getName(), annotation),
|
||||
it -> new ModuleTestExecution(annotation, modules, module));
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.modulith.test.PublishedEvents.TypedPublishedEvents;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.modulith.test;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.ParameterContext;
|
||||
@@ -35,8 +36,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCallback {
|
||||
|
||||
private ThreadBoundApplicationListenerAdapter listener;
|
||||
private final Function<ExtensionContext, ApplicationContext> lookup;
|
||||
private @Nullable ThreadBoundApplicationListenerAdapter listener;
|
||||
|
||||
PublishedEventsParameterResolver() {
|
||||
this(ctx -> SpringExtension.getApplicationContext(ctx));
|
||||
@@ -74,7 +75,10 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa
|
||||
var publishedEvents = PublishedEventsFactory.createPublishedEvents();
|
||||
|
||||
initializeListener(extensionContext);
|
||||
listener.registerDelegate(publishedEvents);
|
||||
|
||||
if (listener != null) {
|
||||
listener.registerDelegate(publishedEvents);
|
||||
}
|
||||
|
||||
return publishedEvents;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.core.ConditionFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.lang.CheckReturnValue;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.modulith.test.PublishedEvents.TypedPublishedEvents;
|
||||
import org.springframework.modulith.test.PublishedEventsAssert.PublishedEventAssert;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
@@ -96,7 +96,13 @@ public class Scenario {
|
||||
var definition = new DefaultTransactionDefinition(transactionTemplate);
|
||||
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
||||
this.transactionOperations = new TransactionTemplate(transactionTemplate.getTransactionManager(), definition);
|
||||
var transactionManager = transactionTemplate.getTransactionManager();
|
||||
|
||||
if (transactionManager == null) {
|
||||
throw new IllegalStateException("No transaction manager found on TransactionTemplate!");
|
||||
}
|
||||
|
||||
this.transactionOperations = new TransactionTemplate(transactionManager, definition);
|
||||
this.publisher = publisher;
|
||||
this.events = events;
|
||||
this.defaultCustomizer = Function.identity();
|
||||
@@ -498,7 +504,7 @@ public class Scenario {
|
||||
|
||||
private final Class<E> type;
|
||||
private final Function<TypedPublishedEvents<E>, TypedPublishedEvents<E>> filter;
|
||||
private final ExecutionResult<?, T> previousResult;
|
||||
private final @Nullable ExecutionResult<?, T> previousResult;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EventResult} for the given type and filter.
|
||||
@@ -508,7 +514,7 @@ public class Scenario {
|
||||
* @param previousResult a potentially previously calculated result.
|
||||
*/
|
||||
EventResult(Class<E> type, Function<TypedPublishedEvents<E>, TypedPublishedEvents<E>> filtered,
|
||||
ExecutionResult<?, T> previousResult) {
|
||||
@Nullable ExecutionResult<?, T> previousResult) {
|
||||
|
||||
Assert.notNull(type, "Event type must not be null!");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Integration test support for Spring Modulith {@link org.springframework.modulith.core.ApplicationModules}.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package org.springframework.modulith.test;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.modulith.test.ScenarioCustomizerIntegrationTests.Test
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
/**
|
||||
@@ -53,7 +54,10 @@ class ScenarioCustomizerIntegrationTests {
|
||||
|
||||
@Bean
|
||||
TransactionTemplate transactionTemplate() {
|
||||
return mock(TransactionTemplate.class);
|
||||
|
||||
var txManager = mock(PlatformTransactionManager.class);
|
||||
|
||||
return new TransactionTemplate(txManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
Reference in New Issue
Block a user