diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 07edae63..2c9e3a72 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,4 +31,4 @@ jobs: ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - run: ./mvnw -B clean deploy -Pci,artifactory + run: ./mvnw -B clean deploy -Pci,artifactory,nullaway diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 00000000..32599cef --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1,10 @@ +--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/pom.xml b/pom.xml index 20d6b09a..83bed74a 100644 --- a/pom.xml +++ b/pom.xml @@ -37,10 +37,12 @@ 1.4.0 3.6.2 + 2.36.0 4.16.1 7.0.0.202409031743-r 1.5.2 2023.3.1 + 0.12.7 UTF-8 UTF-8 4.0.0-SNAPSHOT @@ -431,6 +433,54 @@ limitations under the License. + + nullaway + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + + + + + default-compile + none + + + java-compile + compile + + compile + + + + + com.google.errorprone + error_prone_core + ${errorprone.version} + + + com.uber.nullaway + nullaway + ${nullaway.version} + + + + -XDcompilePolicy=simple + --should-stop=ifError=FLOW + -Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:CustomContractAnnotations=org.springframework.lang.Contract + + + + + + + + + diff --git a/spring-modulith-actuator/pom.xml b/spring-modulith-actuator/pom.xml index 671129ba..c590ead6 100644 --- a/spring-modulith-actuator/pom.xml +++ b/spring-modulith-actuator/pom.xml @@ -16,6 +16,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-runtime diff --git a/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/autoconfigure/package-info.java b/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/autoconfigure/package-info.java index d81ff6fc..113b0d46 100644 --- a/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/autoconfigure/package-info.java +++ b/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/autoconfigure/package-info.java @@ -1,5 +1,5 @@ /** * Autoconfiguration for Spring Modulith actuators. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.actuator.autoconfigure; diff --git a/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/package-info.java b/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/package-info.java index 19489a32..b1ad5399 100644 --- a/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/package-info.java +++ b/spring-modulith-actuator/src/main/java/org/springframework/modulith/actuator/package-info.java @@ -1,5 +1,5 @@ /** * Spring Boot actuator support for Spring Modulith. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.actuator; diff --git a/spring-modulith-api/pom.xml b/spring-modulith-api/pom.xml index 3d12d714..6fbb6094 100644 --- a/spring-modulith-api/pom.xml +++ b/spring-modulith-api/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.boot spring-boot-autoconfigure diff --git a/spring-modulith-api/src/main/java/org/springframework/modulith/package-info.java b/spring-modulith-api/src/main/java/org/springframework/modulith/package-info.java index b308e837..b35ed2b0 100644 --- a/spring-modulith-api/src/main/java/org/springframework/modulith/package-info.java +++ b/spring-modulith-api/src/main/java/org/springframework/modulith/package-info.java @@ -1,5 +1,5 @@ /** * Core abstractions of Spring Modulith. To be referred to in user applications. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith; diff --git a/spring-modulith-apt/pom.xml b/spring-modulith-apt/pom.xml index cfae0220..3b6778f3 100644 --- a/spring-modulith-apt/pom.xml +++ b/spring-modulith-apt/pom.xml @@ -21,6 +21,10 @@ aptk-tools 0.29.0 + + org.jspecify + jspecify + org.springframework.boot diff --git a/spring-modulith-apt/src/main/java/org/springframework/modulith/apt/SpringModulithProcessor.java b/spring-modulith-apt/src/main/java/org/springframework/modulith/apt/SpringModulithProcessor.java index 04008243..4cf88144 100644 --- a/spring-modulith-apt/src/main/java/org/springframework/modulith/apt/SpringModulithProcessor.java +++ b/spring-modulith-apt/src/main/java/org/springframework/modulith/apt/SpringModulithProcessor.java @@ -19,6 +19,7 @@ import io.toolisticon.aptk.tools.ElementUtils; import io.toolisticon.aptk.tools.wrapper.ElementWrapper; import io.toolisticon.aptk.tools.wrapper.ExecutableElementWrapper; import io.toolisticon.aptk.tools.wrapper.TypeElementWrapper; +import org.jspecify.annotations.Nullable; import java.io.File; import java.io.FileWriter; @@ -50,7 +51,6 @@ import javax.tools.Diagnostic.Kind; import javax.tools.StandardLocation; import org.springframework.boot.json.JsonWriter; -import org.springframework.lang.Nullable; import org.springframework.modulith.docs.metadata.MethodMetadata; import org.springframework.modulith.docs.metadata.TypeMetadata; import org.springframework.modulith.docs.util.BuildSystemUtils; diff --git a/spring-modulith-core/pom.xml b/spring-modulith-core/pom.xml index e936aabe..a58bf73f 100644 --- a/spring-modulith-core/pom.xml +++ b/spring-modulith-core/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-api diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java index 621feaed..0aa1a280 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java @@ -36,7 +36,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.core.Types.JMoleculesTypes; import org.springframework.modulith.core.Types.JavaTypes; import org.springframework.modulith.core.Types.SpringTypes; @@ -427,7 +427,7 @@ public class ApplicationModule implements Comparable { var candidatePackageName = PackageName.ofType(candidate); - return (candidatePackageName.isEmpty() || basePackage.getPackageName().contains(candidatePackageName)) + return (PackageName.isDefault(candidatePackageName) || basePackage.getPackageName().contains(candidatePackageName)) && getType(candidate).isPresent(); } diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleDependencies.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleDependencies.java index 03f0be13..2536b2c6 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleDependencies.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleDependencies.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; /** @@ -172,7 +173,7 @@ public class ApplicationModuleDependencies { * @param name must not be {@literal null} or empty. * @return will never be {@literal null}. */ - public ApplicationModule getModuleByType(String name) { + public @Nullable ApplicationModule getModuleByType(String name) { Assert.hasText(name, "Name must not be null or empty!"); diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSource.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSource.java index 3a9a8cfb..29ed250b 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSource.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSource.java @@ -21,6 +21,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.ApplicationModule; import org.springframework.modulith.core.Types.JMoleculesTypes; import org.springframework.util.Assert; @@ -240,7 +241,7 @@ public class ApplicationModuleSource { * @param delegates must not be {@literal null}. * @return will never be {@literal null}. */ - private static ApplicationModuleSourceMetadata delegating(ApplicationModuleSourceMetadata... delegates) { + private static ApplicationModuleSourceMetadata delegating(@Nullable ApplicationModuleSourceMetadata... delegates) { return new ApplicationModuleSourceMetadata() { diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSourceFactory.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSourceFactory.java index 5f00f973..22276da1 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSourceFactory.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleSourceFactory.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * SPI to allow build units contribute additional {@link ApplicationModuleSource}s in the form of either declaring them diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModules.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModules.java index 390b0ccc..92699336 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModules.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModules.java @@ -32,9 +32,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.jspecify.annotations.Nullable; import org.springframework.aot.generate.Generated; import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.function.SingletonSupplier; @@ -61,7 +61,7 @@ public class ApplicationModules implements Iterable { private static final Map CACHE = new ConcurrentHashMap<>(); private static final ImportOption IMPORT_OPTION = new ImportOption.DoNotIncludeTests(); - private static final DescribedPredicate IS_GENERATED; + private static final @Nullable DescribedPredicate IS_GENERATED; private static final DescribedPredicate IS_SPRING_CGLIB_PROXY = nameContaining("$$SpringCGLIB$$"); static { @@ -624,9 +624,9 @@ public class ApplicationModules implements Iterable { * {@literal null} or its type does not reside in any module. * * @param object can be {@literal null}. - * @return + * @return can be {@literal null}. */ - private Integer getModuleIndexFor(@Nullable Object object) { + private @Nullable Integer getModuleIndexFor(@Nullable Object object) { return Optional.ofNullable(object) .map(it -> Class.class.isInstance(it) ? Class.class.cast(it) : it.getClass()) @@ -778,7 +778,7 @@ public class ApplicationModules implements Iterable { * @see java.lang.Object#equals(java.lang.Object) */ @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj == this) { return true; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ArchitecturallyEvidentType.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ArchitecturallyEvidentType.java index 5e6d1606..5f49f518 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ArchitecturallyEvidentType.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ArchitecturallyEvidentType.java @@ -20,6 +20,7 @@ import static org.springframework.modulith.core.Types.JavaXTypes.*; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -676,7 +677,9 @@ public abstract class ArchitecturallyEvidentType { var attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(method.reflect(), SpringTypes.AT_EVENT_LISTENER, false, false); - return List.of(attributes.getClassArray("classes")); + return attributes == null + ? Collections.emptyList() + : List.of(attributes.getClassArray("classes")); } /* diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Classes.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Classes.java index 6d3bf3ef..f118f234 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Classes.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Classes.java @@ -29,7 +29,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/FormattableType.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/FormattableType.java index 656d55d7..3516b01a 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/FormattableType.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/FormattableType.java @@ -22,7 +22,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ModulithMetadata.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ModulithMetadata.java index 98c16998..2822e711 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ModulithMetadata.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ModulithMetadata.java @@ -75,7 +75,12 @@ public interface ModulithMetadata { return SpringBootModulithMetadata.of(javaPackage); } - var className = candidates.iterator().next().getBeanClassName(); + var definition = candidates.iterator().next(); + var className = definition.getBeanClassName(); + + if (className == null) { + throw new IllegalStateException("No bean class name found on BeanDefinition %s!".formatted(definition)); + } return of(ClassUtils.resolveClassName(className, ModulithMetadata.class.getClassLoader())); } diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterfaces.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterfaces.java index e5223534..bb21f161 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterfaces.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterfaces.java @@ -298,6 +298,10 @@ public class NamedInterfaces implements Iterable { var annotation = AnnotatedElementUtils.getMergedAnnotation(it.reflect(), org.springframework.modulith.NamedInterface.class); + if (annotation == null) { + throw new IllegalStateException("No @NamedInterface annotation found!"); + } + NamedInterface.getDefaultedNames(annotation, it.getPackageName()) .forEach(name -> mappings.add(name, it)); }); diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/PackageName.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/PackageName.java index c62ca790..7c2e95ed 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/PackageName.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/PackageName.java @@ -18,10 +18,11 @@ package org.springframework.modulith.core; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -34,6 +35,8 @@ import org.springframework.util.ClassUtils; */ public class PackageName implements Comparable { + public static final String DEFAULT = "<>"; + private static final Map PACKAGE_NAMES = new HashMap<>(); private final String name; @@ -77,6 +80,20 @@ public class PackageName implements Comparable { return PackageName.of(ClassUtils.getPackageName(fullyQualifiedName)); } + /** + * Creates a new {@link PackageName} for the given fully-qualified type name. + * + * @param fullyQualifiedName must not be {@literal null} or empty. + * @return will never be {@literal null}. + * @since 2.0 + */ + public static PackageName ofType(Class type) { + + Assert.notNull(type, "Type must not be null!"); + + return PackageName.of(ClassUtils.getPackageName(type)); + } + /** * Returns the {@link PackageName} with the given name. * @@ -88,7 +105,9 @@ public class PackageName implements Comparable { Assert.notNull(name, "Name must not be null!"); - return PACKAGE_NAMES.computeIfAbsent(name, PackageName::new); + var defaulted = name.isBlank() ? DEFAULT : name; + + return PACKAGE_NAMES.computeIfAbsent(defaulted, PackageName::new); } /** @@ -107,6 +126,16 @@ public class PackageName implements Comparable { return PACKAGE_NAMES.computeIfAbsent(name, it -> new PackageName(name, segments)); } + /** + * Returns whether the given {@link PackageName} is the default package name (logically an empty string). + * + * @param name must not be {@literal null}. + * @since 2.0 + */ + static boolean isDefault(PackageName name) { + return name.hasName(DEFAULT); + } + /** * Returns the length of the package name. * @@ -281,7 +310,9 @@ public class PackageName implements Comparable { return Stream.of(reference); } - return Stream.concat(expandUntil(reference.getParent()), Stream.of(reference)); + var parent = Objects.requireNonNull(reference.getParent()); + + return Stream.concat(expandUntil(parent), Stream.of(reference)); } /** @@ -318,7 +349,7 @@ public class PackageName implements Comparable { * @see java.lang.Object#equals(java.lang.Object) */ @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj == this) { return true; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBootModulithMetadata.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBootModulithMetadata.java index 57a54e3e..85458a29 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBootModulithMetadata.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBootModulithMetadata.java @@ -21,8 +21,8 @@ import java.util.List; import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.lang.NonNull; import org.springframework.modulith.core.Types.SpringTypes; import org.springframework.util.Assert; @@ -34,20 +34,21 @@ import org.springframework.util.Assert; */ class SpringBootModulithMetadata implements ModulithMetadata { - private static final Class AT_SPRING_BOOT_APPLICATION = Types + private static final @Nullable Class AT_SPRING_BOOT_APPLICATION = Types .loadIfPresent(SpringTypes.AT_SPRING_BOOT_APPLICATION); - private final @NonNull Object source; - private final String systemName, basePackage; + private final Object source; + private final String basePackage; + private final @Nullable String systemName; /** * Creates a new {@link SpringBootModulithMetadata} for the given source. * * @param source must not be {@literal null}. - * @param systemName can be {@literal null}. * @param basePackage must not be {@literal null}. + * @param systemName can be {@literal null}. */ - private SpringBootModulithMetadata(Object source, String systemName, String basePackage) { + private SpringBootModulithMetadata(Object source, String basePackage, @Nullable String systemName) { Assert.notNull(source, "Source must not be null!"); Assert.notNull(basePackage, "Base package must not be null!"); @@ -71,7 +72,7 @@ class SpringBootModulithMetadata implements ModulithMetadata { return Optional.ofNullable(AT_SPRING_BOOT_APPLICATION) // .filter(it -> AnnotatedElementUtils.hasAnnotation(annotated, it)) // - .map(__ -> new SpringBootModulithMetadata(annotated, annotated.getSimpleName(), annotated.getPackageName())); + .map(__ -> new SpringBootModulithMetadata(annotated, annotated.getPackageName(), annotated.getSimpleName())); } /** @@ -84,7 +85,7 @@ class SpringBootModulithMetadata implements ModulithMetadata { Assert.hasText(javaPackage, "Package name must not be null or empty!"); - return new SpringBootModulithMetadata(javaPackage, null, javaPackage); + return new SpringBootModulithMetadata(javaPackage, javaPackage, null); } /* diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java index 70b4c372..048d74b3 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java @@ -26,7 +26,7 @@ import java.util.function.Predicate; import org.jmolecules.archunit.JMoleculesArchitectureRules; import org.jmolecules.archunit.JMoleculesDddRules; import org.jmolecules.ddd.annotation.Module; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.PackageInfo; import org.springframework.modulith.core.ApplicationModuleSource.ApplicationModuleSourceMetadata; import org.springframework.util.Assert; @@ -82,7 +82,7 @@ public class Types { static final String AT_DOMAIN_EVENT = BASE_PACKAGE + ".event.annotation.DomainEvent"; static final String DOMAIN_EVENT = BASE_PACKAGE + ".event.types.DomainEvent"; - private static Collection RULES; + private static @Nullable Collection RULES; /** * Returns whether jMolecules is generally present. @@ -123,34 +123,38 @@ public class Types { */ public static Collection getRules() { - if (RULES == null) { + var rules = RULES; + + if (rules == null) { var classLoader = JMoleculesTypes.class.getClassLoader(); - RULES = new ArrayList(); + rules = new ArrayList(); if (ClassUtils.isPresent(DDD_RULES, classLoader)) { - RULES.add(JMoleculesDddRules.all()); + rules.add(JMoleculesDddRules.all()); } if (!ClassUtils.isPresent(ARCHITECTURE_RULES, classLoader)) { - return RULES; + return rules; } if (ClassUtils.isPresent(HEXAGONAL, classLoader)) { - RULES.add(JMoleculesArchitectureRules.ensureHexagonal()); + rules.add(JMoleculesArchitectureRules.ensureHexagonal()); } if (ClassUtils.isPresent(LAYERED, classLoader)) { - RULES.add(JMoleculesArchitectureRules.ensureLayering()); + rules.add(JMoleculesArchitectureRules.ensureLayering()); } if (ClassUtils.isPresent(ONION, classLoader)) { - RULES.add(JMoleculesArchitectureRules.ensureOnionClassical()); - RULES.add(JMoleculesArchitectureRules.ensureOnionSimple()); + rules.add(JMoleculesArchitectureRules.ensureOnionClassical()); + rules.add(JMoleculesArchitectureRules.ensureOnionSimple()); } + + RULES = rules; } - return RULES; + return rules; } } diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/config/package-info.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/config/package-info.java index 488ce2d5..5ce3aeeb 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/config/package-info.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/config/package-info.java @@ -1,5 +1,5 @@ /** * Core configuration abstractions of Spring Modulith. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.core.config; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/package-info.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/package-info.java index b9eca324..2321e3ea 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/package-info.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/package-info.java @@ -1,5 +1,5 @@ /** * Core, internal abstractions of Spring Modulith. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.core; diff --git a/spring-modulith-core/src/test/java/org/springframework/modulith/core/ApplicationModulesUnitTests.java b/spring-modulith-core/src/test/java/org/springframework/modulith/core/ApplicationModulesUnitTests.java index c1cb9438..9ed32289 100644 --- a/spring-modulith-core/src/test/java/org/springframework/modulith/core/ApplicationModulesUnitTests.java +++ b/spring-modulith-core/src/test/java/org/springframework/modulith/core/ApplicationModulesUnitTests.java @@ -80,4 +80,12 @@ class ApplicationModulesUnitTests { it -> assertThat(it).contains("Invalid", "'invalid'", "'ni.nested.b.first'"), it -> assertThat(it).contains("Invalid", "'ni'", "'ni.nested.b.first'")); } + + @Test // GH-1192 + void findsTypeBySimpleName() { + + assertThat(modules.getModuleByName("ni")).hasValueSatisfying(it -> { + assertThat(it.contains("RootType")).isTrue(); + }); + } } diff --git a/spring-modulith-docs/pom.xml b/spring-modulith-docs/pom.xml index 42dcdcb8..51d3d4e3 100644 --- a/spring-modulith-docs/pom.xml +++ b/spring-modulith-docs/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-core diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Asciidoctor.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Asciidoctor.java index 33fa69c1..b5d0f69c 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Asciidoctor.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Asciidoctor.java @@ -25,9 +25,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.lang.Nullable; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModuleDependency; import org.springframework.modulith.core.ApplicationModules; diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/ConfigurationProperties.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/ConfigurationProperties.java index 4eae7425..1f0666e6 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/ConfigurationProperties.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/ConfigurationProperties.java @@ -23,9 +23,9 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.lang.Nullable; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.docs.ConfigurationProperties.ConfigurationProperty; import org.springframework.util.Assert; @@ -124,7 +124,6 @@ class ConfigurationProperties implements Iterable { static record ConfigurationProperty(String name, @Nullable String description, String type, String sourceType, @Nullable String defaultValue) { - @SuppressWarnings("null") static Stream of(Map source) { String sourceType = getAsString(source, "sourceType"); @@ -133,9 +132,9 @@ class ConfigurationProperties implements Iterable { return Stream.empty(); } - ConfigurationProperty property = new ConfigurationProperty(getAsString(source, "name"), + ConfigurationProperty property = new ConfigurationProperty(getRequiredAsString(source, "name"), getAsString(source, "description"), - getAsString(source, "type"), + getRequiredAsString(source, "type"), sourceType, getAsString(source, "defaultValue")); @@ -146,6 +145,15 @@ class ConfigurationProperties implements Iterable { return StringUtils.hasText(sourceType); } + private static String getRequiredAsString(Map source, String key) { + + var value = getAsString(source, key); + + Assert.notNull(value, "No value found for key %s in %s!".formatted(key, source)); + + return value; + } + private static @Nullable String getAsString(Map source, String key) { Object value = source.get(key); diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java index f2890a7f..0bf912aa 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java @@ -36,7 +36,8 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; +import org.springframework.lang.Contract; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModules; import org.springframework.modulith.core.DependencyDepth; @@ -98,7 +99,7 @@ public class Documenter { private boolean cleared; - private Map components; + private @Nullable Map components; /** * Creates a new {@link Documenter} for the {@link ApplicationModules} created for the given modulith type in the @@ -223,6 +224,7 @@ public class Documenter { * @return the current instance, will never be {@literal null}. * @since 1.2.2 */ + @Contract("_, _ -> this") public Documenter writeAggregatingDocument(DiagramOptions diagramOptions, CanvasOptions canvasOptions) { Assert.notNull(diagramOptions, "DiagramOptions must not be null!"); @@ -485,18 +487,19 @@ public class Documenter { .forEach(it -> it.addTags(DependencyType.USES_COMPONENT.toString())); } + @SuppressWarnings("null") private Map getComponents(DiagramOptions options) { - if (components == null) { + if (this.components == null) { this.components = modules.stream() // .collect(Collectors.toMap(Function.identity(), it -> container.addComponent(options.defaultDisplayName.apply(it), "", "Module"))); - this.components.forEach((key, value) -> addDependencies(key, value, options)); + components.forEach((key, value) -> addDependencies(key, value, options)); } - return components; + return this.components; } private void addComponentsToView(ApplicationModule module, ComponentView view, DiagramOptions options) { @@ -643,6 +646,11 @@ public class Documenter { Styles styles) { var component = components.get(module); + + if (component == null) { + throw new IllegalStateException("Couldn't find component for module %s!".formatted(module)); + } + var selector = options.colorSelector; // Apply custom color if configured @@ -1061,6 +1069,7 @@ public class Documenter { return new CanvasOptions(groupers, apiBase, targetFileName, hideInternals, hideEmptyLines); } + @Nullable String getApiBase() { return apiBase; } @@ -1083,7 +1092,10 @@ public class Documenter { // Wipe entries without any beans new HashSet<>(result.keySet()).forEach(key -> { - if (result.get(key).isEmpty()) { + + var value = result.get(key); + + if (value != null && value.isEmpty()) { result.remove(key); } }); @@ -1161,10 +1173,10 @@ public class Documenter { * * @param name must not be {@literal null} or empty. * @param predicate must not be {@literal null}. - * @param description must not be {@literal null} or empty. + * @param description can be {@literal null}. * @return will never be {@literal null}. */ - public static Grouping of(String name, Predicate predicate, String description) { + public static Grouping of(String name, Predicate predicate, @Nullable String description) { return new Grouping(name, predicate, description); } diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/SpringModulithDocumentationSource.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/SpringModulithDocumentationSource.java index c6c77971..c6aa46f5 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/SpringModulithDocumentationSource.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/SpringModulithDocumentationSource.java @@ -23,9 +23,9 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.boot.json.BasicJsonParser; import org.springframework.core.io.Resource; -import org.springframework.lang.Nullable; import org.springframework.modulith.docs.metadata.MethodMetadata; import org.springframework.modulith.docs.metadata.TypeMetadata; import org.springframework.modulith.docs.util.BuildSystemUtils; @@ -134,28 +134,39 @@ class SpringModulithDocumentationSource implements DocumentationSource { @SuppressWarnings("unchecked") private static TypeMetadata typeMetadata(Map source) { - var methods = source.containsKey("methods") - ? ((List>) source.get("methods")).stream() - .map(SpringModulithDocumentationSource::methodMetadata) - .toList() + var sourceMethods = (List>) source.get("methods"); + + var methods = sourceMethods != null + ? sourceMethods.stream().map(SpringModulithDocumentationSource::methodMetadata).toList() : Collections. emptyList(); - return new TypeMetadata( - source.get("name").toString(), - getString(source, "comment"), - methods); + var name = source.get("name"); + + if (name == null) { + throw new IllegalArgumentException("Source map does not contain a name entry! %s".formatted(source)); + } + + return new TypeMetadata(name.toString(), getString(source, "comment"), methods); } private static MethodMetadata methodMetadata(Map source) { - return new MethodMetadata( - source.get("name").toString(), - source.get("signature").toString(), - getString(source, "comment")); + var name = source.get("name"); + + if (name == null) { + throw new IllegalArgumentException("No name found in source map! %s".formatted(source)); + } + + var signature = source.get("signature"); + + if (signature == null) { + throw new IllegalArgumentException("No signature found in source map! %s".formatted(source)); + } + + return new MethodMetadata(name.toString(), signature.toString(), getString(source, "comment")); } - @Nullable - private static String getString(Map source, String key) { + private static @Nullable String getString(Map source, String key) { Object result = source.get(key); diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/MethodMetadata.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/MethodMetadata.java index bb8a458a..a224c4c1 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/MethodMetadata.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/MethodMetadata.java @@ -19,7 +19,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.stream.Collectors; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; /** diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/TypeMetadata.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/TypeMetadata.java index 046c57d4..6a9ee7e2 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/TypeMetadata.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/metadata/TypeMetadata.java @@ -17,7 +17,7 @@ package org.springframework.modulith.docs.metadata; import java.util.List; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Metadata about a Java type. diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/package-info.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/package-info.java index 3e33c847..0eaac944 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/package-info.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/package-info.java @@ -1,5 +1,5 @@ /** * Documentation support for Spring Modulith. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.docs; diff --git a/spring-modulith-events/spring-modulith-events-amqp/pom.xml b/spring-modulith-events/spring-modulith-events-amqp/pom.xml index 520fac2a..a9991c83 100644 --- a/spring-modulith-events/spring-modulith-events-amqp/pom.xml +++ b/spring-modulith-events/spring-modulith-events-amqp/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-api diff --git a/spring-modulith-events/spring-modulith-events-amqp/src/main/java/org/springframework/modulith/events/amqp/package-info.java b/spring-modulith-events/spring-modulith-events-amqp/src/main/java/org/springframework/modulith/events/amqp/package-info.java index cd2ad293..c64a1263 100644 --- a/spring-modulith-events/spring-modulith-events-amqp/src/main/java/org/springframework/modulith/events/amqp/package-info.java +++ b/spring-modulith-events/spring-modulith-events-amqp/src/main/java/org/springframework/modulith/events/amqp/package-info.java @@ -1,5 +1,5 @@ /** * AMQP event externalization support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.amqp; diff --git a/spring-modulith-events/spring-modulith-events-api/pom.xml b/spring-modulith-events/spring-modulith-events-api/pom.xml index a5d5bb6c..e8dd5937 100644 --- a/spring-modulith-events/spring-modulith-events-api/pom.xml +++ b/spring-modulith-events/spring-modulith-events-api/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework spring-context diff --git a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/AnnotationTargetLookup.java b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/AnnotationTargetLookup.java index 05f92ef2..c01288d3 100644 --- a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/AnnotationTargetLookup.java +++ b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/AnnotationTargetLookup.java @@ -25,6 +25,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.events.RoutingTarget.ParsedRoutingTarget; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -45,7 +46,7 @@ class AnnotationTargetLookup implements Supplier> private static Map, AnnotationTargetLookup> LOOKUPS = new ConcurrentReferenceHashMap<>(25); private static final String JMOLECULES_EXTERNALIZED = "org.jmolecules.event.annotation.Externalized"; - private static final Class JMOLECULES_ANNOTATION = loadJMoleculesExternalizedIfPresent(); + private static final @Nullable Class JMOLECULES_ANNOTATION = loadJMoleculesExternalizedIfPresent(); private final Class type; private final Supplier> lookup; @@ -159,7 +160,7 @@ class AnnotationTargetLookup implements Supplier> } @SuppressWarnings("unchecked") - private static Class loadJMoleculesExternalizedIfPresent() { + private static @Nullable Class loadJMoleculesExternalizedIfPresent() { var classLoader = DefaultEventExternalizationConfiguration.class.getClassLoader(); diff --git a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalizationConfiguration.java b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalizationConfiguration.java index 9d388926..0af34468 100644 --- a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalizationConfiguration.java +++ b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalizationConfiguration.java @@ -28,8 +28,8 @@ import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.RoutingTarget.ParsedRoutingTarget; import org.springframework.modulith.events.RoutingTarget.RoutingTargetBuilder; import org.springframework.util.Assert; @@ -359,7 +359,16 @@ public interface EventExternalizationConfiguration { } private static T findAnnotation(Object event, Class annotationType) { - return findMergedAnnotation(event.getClass(), annotationType); + + var type = event.getClass(); + var result = findMergedAnnotation(type, annotationType); + + if (result == null) { + throw new IllegalStateException( + "Couldn't find annotation %s on type %s!".formatted(annotationType, type)); + } + + return result; } } diff --git a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalized.java b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalized.java index 3ca11255..79ce5737 100644 --- a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalized.java +++ b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/EventExternalized.java @@ -17,9 +17,10 @@ package org.springframework.modulith.events; import java.util.Objects; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableTypeProvider; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -103,7 +104,7 @@ public class EventExternalized implements ResolvableTypeProvider { * * @return can be {@literal null}. */ - public T getBrokerResult() { + public @Nullable T getBrokerResult() { return brokerResult; } @@ -112,7 +113,7 @@ public class EventExternalized implements ResolvableTypeProvider { * @see org.springframework.core.ResolvableTypeProvider#getResolvableType() */ @Override - public ResolvableType getResolvableType() { + public @NonNull ResolvableType getResolvableType() { return type; } diff --git a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/RoutingTarget.java b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/RoutingTarget.java index 2d281330..806b1b9f 100644 --- a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/RoutingTarget.java +++ b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/RoutingTarget.java @@ -17,7 +17,7 @@ package org.springframework.modulith.events; import java.util.Objects; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -238,14 +238,14 @@ public class RoutingTarget { /** * @return the target */ - public String getTarget() { + public @Nullable String getTarget() { return target; } /** * @return the key */ - public String getKey() { + public @Nullable String getKey() { return key; } diff --git a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/package-info.java b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/package-info.java index 0f3c9311..22487c23 100644 --- a/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/package-info.java +++ b/spring-modulith-events/spring-modulith-events-api/src/main/java/org/springframework/modulith/events/package-info.java @@ -1,5 +1,5 @@ /** * API of the event publication registry abstraction. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events; diff --git a/spring-modulith-events/spring-modulith-events-core/pom.xml b/spring-modulith-events/spring-modulith-events-core/pom.xml index f248b37c..cadaf6db 100644 --- a/spring-modulith-events/spring-modulith-events-core/pom.xml +++ b/spring-modulith-events/spring-modulith-events-core/pom.xml @@ -17,6 +17,11 @@ + + + org.jspecify + jspecify + org.springframework.modulith diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/ApplicationListenerMethodAdapterRuntimeHints.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/ApplicationListenerMethodAdapterRuntimeHints.java index 9f4028b4..ad35b9c2 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/ApplicationListenerMethodAdapterRuntimeHints.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/ApplicationListenerMethodAdapterRuntimeHints.java @@ -15,6 +15,7 @@ */ package org.springframework.modulith.events.aot; +import org.jspecify.annotations.Nullable; import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; @@ -32,7 +33,7 @@ public class ApplicationListenerMethodAdapterRuntimeHints implements RuntimeHint * @see org.springframework.aot.hint.RuntimeHintsRegistrar#registerHints(org.springframework.aot.hint.RuntimeHints, java.lang.ClassLoader) */ @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { var reflection = hints.reflection(); diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/TransactionalEventListenerAotProcessor.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/TransactionalEventListenerAotProcessor.java index d75d990f..c2b0bc28 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/TransactionalEventListenerAotProcessor.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/TransactionalEventListenerAotProcessor.java @@ -17,6 +17,7 @@ package org.springframework.modulith.events.aot; import java.util.Arrays; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aot.hint.MemberCategory; @@ -43,7 +44,7 @@ public class TransactionalEventListenerAotProcessor implements BeanRegistrationA * @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor#processAheadOfTime(org.springframework.beans.factory.support.RegisteredBean) */ @Override - public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { Class type = registeredBean.getBeanType().resolve(Object.class); diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/package-info.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/package-info.java index 956013cf..8d2603fc 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/package-info.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/aot/package-info.java @@ -1,5 +1,5 @@ /** * AOT support for the Event Publication Registry. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.aot; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/EventPublicationAutoConfiguration.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/EventPublicationAutoConfiguration.java index d0160200..96f41a40 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/EventPublicationAutoConfiguration.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/EventPublicationAutoConfiguration.java @@ -19,6 +19,7 @@ import java.time.Clock; import java.time.Duration; import java.util.Arrays; +import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -37,7 +38,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Role; import org.springframework.core.env.Environment; -import org.springframework.lang.NonNull; import org.springframework.modulith.events.config.EventPublicationAutoConfiguration.AsyncEnablingConfiguration; import org.springframework.modulith.events.core.DefaultEventPublicationRegistry; import org.springframework.modulith.events.core.EventPublicationRegistry; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/package-info.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/package-info.java index 2d86236d..eae8fc9d 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/package-info.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/config/package-info.java @@ -1,5 +1,5 @@ /** * Spring configuration for the Event Publication Registry. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.config; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublication.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublication.java index c437b7cf..bec660e7 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublication.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublication.java @@ -20,7 +20,7 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; /** diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java index 7fc1a8f4..8c90e5ed 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/DefaultEventPublicationRegistry.java @@ -27,10 +27,10 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.CompletedEventPublications; import org.springframework.modulith.events.EventPublication; import org.springframework.transaction.annotation.Propagation; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/EventPublicationRegistry.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/EventPublicationRegistry.java index 31f86fdf..6f6b7dc6 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/EventPublicationRegistry.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/EventPublicationRegistry.java @@ -21,8 +21,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationListener; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.EventPublication; /** diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/PublicationTargetIdentifier.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/PublicationTargetIdentifier.java index ddc80d3d..fb50fb10 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/PublicationTargetIdentifier.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/PublicationTargetIdentifier.java @@ -17,7 +17,7 @@ package org.springframework.modulith.events.core; import java.util.Objects; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; /** diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/package-info.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/package-info.java index a50857e9..82730293 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/package-info.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/core/package-info.java @@ -1,5 +1,5 @@ /** * The event publication registry abstraction. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.core; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/BrokerRouting.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/BrokerRouting.java index 99bb1e01..f13725ed 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/BrokerRouting.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/BrokerRouting.java @@ -15,11 +15,11 @@ */ package org.springframework.modulith.events.support; +import org.jspecify.annotations.Nullable; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.RoutingTarget; import org.springframework.util.Assert; diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/CompletionRegisteringAdvisor.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/CompletionRegisteringAdvisor.java index 1efd6597..ef8f4226 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/CompletionRegisteringAdvisor.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/CompletionRegisteringAdvisor.java @@ -22,6 +22,8 @@ import java.util.function.Supplier; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.MethodMatcher; @@ -31,7 +33,6 @@ import org.springframework.aop.support.StaticMethodMatcher; import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.lang.NonNull; import org.springframework.modulith.events.core.EventPublicationRegistry; import org.springframework.modulith.events.core.PublicationTargetIdentifier; import org.springframework.transaction.event.TransactionPhase; @@ -160,7 +161,7 @@ public class CompletionRegisteringAdvisor extends AbstractPointcutAdvisor { * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Object result = null; var method = invocation.getMethod(); @@ -232,9 +233,8 @@ public class CompletionRegisteringAdvisor extends AbstractPointcutAdvisor { registry.get().markFailed(event, identifier); } - @SuppressWarnings("null") private static String lookupListenerId(Method method) { - return new TransactionalApplicationListenerMethodAdapter(null, method.getDeclaringClass(), method) + return new TransactionalApplicationListenerMethodAdapter("¯\\_(ツ)_/¯", method.getDeclaringClass(), method) .getListenerId(); } } diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/PersistentApplicationEventMulticaster.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/PersistentApplicationEventMulticaster.java index 8ee22a10..925de8e8 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/PersistentApplicationEventMulticaster.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/PersistentApplicationEventMulticaster.java @@ -19,12 +19,15 @@ import java.lang.reflect.Method; import java.time.Duration; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.SmartInitializingSingleton; @@ -36,8 +39,6 @@ import org.springframework.context.event.ApplicationListenerMethodAdapter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.Environment; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.EventPublication; import org.springframework.modulith.events.IncompleteEventPublications; import org.springframework.modulith.events.core.ConditionalEventListener; @@ -64,10 +65,12 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv implements IncompleteEventPublications, SmartInitializingSingleton { private static final Logger LOGGER = LoggerFactory.getLogger(PersistentApplicationEventMulticaster.class); - private static final Method LEGACY_SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class, - "shouldHandle", ApplicationEvent.class, Object[].class); - private static final Method SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class, - "shouldHandle", ApplicationEvent.class); + private static final Method LEGACY_SHOULD_HANDLE = Objects + .requireNonNull(ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class, + "shouldHandle", ApplicationEvent.class, Object[].class)); + private static final Method SHOULD_HANDLE = Objects + .requireNonNull(ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class, + "shouldHandle", ApplicationEvent.class)); static final String REPUBLISH_ON_RESTART = "spring.modulith.events.republish-outstanding-events-on-restart"; static final String REPUBLISH_ON_RESTART_LEGACY = "spring.modulith.republish-outstanding-events-on-restart"; @@ -251,16 +254,19 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv * @param payload the actual payload, must not be {@literal null}. * @return whether the event should be handled by the given candidate. */ - @SuppressWarnings("null") private static boolean invokeShouldHandle(ApplicationListener candidate, ApplicationEvent event, Object payload) { if (!(candidate instanceof ApplicationListenerMethodAdapter listener)) { return true; } - return SHOULD_HANDLE != null - ? listener.shouldHandle(event) - : (boolean) ReflectionUtils.invokeMethod(LEGACY_SHOULD_HANDLE, candidate, event, new Object[] { payload }); + if (SHOULD_HANDLE != null) { + return listener.shouldHandle(event); + } + + var result = ReflectionUtils.invokeMethod(LEGACY_SHOULD_HANDLE, candidate, event, new Object[] { payload }); + + return result == null ? false : (boolean) result; } /** diff --git a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/package-info.java b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/package-info.java index d21f792b..4fc55959 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/package-info.java +++ b/spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/package-info.java @@ -1,5 +1,5 @@ /** * Spring Framework extensions to integrate the event publication registry. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.support; diff --git a/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/config/EventPublicationAutoConfigurationIntegrationTests.java b/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/config/EventPublicationAutoConfigurationIntegrationTests.java index 285a921c..57445bc8 100644 --- a/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/config/EventPublicationAutoConfigurationIntegrationTests.java +++ b/spring-modulith-events/spring-modulith-events-core/src/test/java/org/springframework/modulith/events/config/EventPublicationAutoConfigurationIntegrationTests.java @@ -23,6 +23,7 @@ import java.time.Instant; import java.time.ZoneId; import java.util.function.Function; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -35,7 +36,6 @@ import org.springframework.boot.test.context.assertj.AssertableApplicationContex import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.AdviceMode; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.CompletedEventPublications; import org.springframework.modulith.events.IncompleteEventPublications; import org.springframework.modulith.events.config.EventPublicationAutoConfiguration.AsyncPropertiesDefaulter; diff --git a/spring-modulith-events/spring-modulith-events-jackson/pom.xml b/spring-modulith-events/spring-modulith-events-jackson/pom.xml index 55613728..4282410b 100644 --- a/spring-modulith-events/spring-modulith-events-jackson/pom.xml +++ b/spring-modulith-events/spring-modulith-events-jackson/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-events-core diff --git a/spring-modulith-events/spring-modulith-events-jackson/src/main/java/org/springframework/modulith/events/jackson/package-info.java b/spring-modulith-events/spring-modulith-events-jackson/src/main/java/org/springframework/modulith/events/jackson/package-info.java index e2040964..61f34e2e 100644 --- a/spring-modulith-events/spring-modulith-events-jackson/src/main/java/org/springframework/modulith/events/jackson/package-info.java +++ b/spring-modulith-events/spring-modulith-events-jackson/src/main/java/org/springframework/modulith/events/jackson/package-info.java @@ -1,5 +1,5 @@ /** * A Jackson based implementation of the {@link org.springframework.modulith.events.core.EventSerializer}. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.jackson; diff --git a/spring-modulith-events/spring-modulith-events-jdbc/pom.xml b/spring-modulith-events/spring-modulith-events-jdbc/pom.xml index 7fa853e5..1f9733d3 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/pom.xml +++ b/spring-modulith-events/spring-modulith-events-jdbc/pom.xml @@ -29,6 +29,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-events-core @@ -51,7 +56,6 @@ true - diff --git a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/DatabaseSchemaInitializer.java b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/DatabaseSchemaInitializer.java index 64d97d3e..74d53b1c 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/DatabaseSchemaInitializer.java +++ b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/DatabaseSchemaInitializer.java @@ -16,6 +16,7 @@ package org.springframework.modulith.events.jdbc; import java.sql.Connection; +import java.util.Objects; import javax.sql.DataSource; @@ -39,7 +40,8 @@ class DatabaseSchemaInitializer implements InitializingBean { private final JdbcOperations jdbcOperations; private final JdbcRepositorySettings settings; - DatabaseSchemaInitializer(DataSource dataSource, ResourceLoader resourceLoader, JdbcOperations jdbcOperations, JdbcRepositorySettings settings) { + DatabaseSchemaInitializer(DataSource dataSource, ResourceLoader resourceLoader, JdbcOperations jdbcOperations, + JdbcRepositorySettings settings) { this.dataSource = dataSource; this.resourceLoader = resourceLoader; @@ -63,7 +65,7 @@ class DatabaseSchemaInitializer implements InitializingBean { if (useSchema) { // A schema name has been specified. - if (eventPublicationTableExists(schemaName)) { + if (eventPublicationTableExists(Objects.requireNonNull(schemaName))) { return; } diff --git a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcConfigurationProperties.java b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcConfigurationProperties.java index 816cb4b3..89c475ac 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcConfigurationProperties.java +++ b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcConfigurationProperties.java @@ -15,10 +15,10 @@ */ package org.springframework.modulith.events.jdbc; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.ConstructorBinding; import org.springframework.boot.context.properties.bind.DefaultValue; -import org.springframework.lang.Nullable; /** * Configuration properties for JDBC. @@ -30,7 +30,7 @@ import org.springframework.lang.Nullable; class JdbcConfigurationProperties { private final SchemaInitialization schemaInitialization; - private final String schema; + private final @Nullable String schema; /** * Creates a new {@link JdbcConfigurationProperties} instance. @@ -57,8 +57,7 @@ class JdbcConfigurationProperties { * * @return can be {@literal null}. */ - @Nullable - public String getSchema() { + public @Nullable String getSchema() { return schema; } diff --git a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcEventPublicationRepository.java b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcEventPublicationRepository.java index 6d1eac5d..8fa53dba 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcEventPublicationRepository.java +++ b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcEventPublicationRepository.java @@ -29,11 +29,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.core.EventPublicationRepository; import org.springframework.modulith.events.core.EventSerializer; import org.springframework.modulith.events.core.PublicationTargetIdentifier; @@ -150,7 +150,7 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean INSERT INTO %s (ID, LISTENER_ID, EVENT_TYPE, SERIALIZED_EVENT, PUBLICATION_DATE, COMPLETION_DATE) SELECT ID, LISTENER_ID, EVENT_TYPE, SERIALIZED_EVENT, PUBLICATION_DATE, ? FROM %s - WHERE ID = ? + WHERE ID = ? AND NOT EXISTS (SELECT 1 FROM %s WHERE ID = EVENT_PUBLICATION.ID) """; @@ -161,7 +161,7 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean FROM %s WHERE LISTENER_ID = ? AND SERIALIZED_EVENT = ? - AND NOT EXISTS (SELECT 1 FROM %s WHERE ID = EVENT_PUBLICATION.ID) + AND NOT EXISTS (SELECT 1 FROM %s WHERE ID = EVENT_PUBLICATION.ID) """; private static final int DELETE_BATCH_SIZE = 100; @@ -170,7 +170,7 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean private final EventSerializer serializer; private final JdbcRepositorySettings settings; - private ClassLoader classLoader; + private @Nullable ClassLoader classLoader; private final String sqlStatementInsert, sqlStatementFindCompleted, @@ -222,8 +222,10 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean this.sqlStatementDeleteById = SQL_STATEMENT_DELETE_BY_ID.formatted(table); this.sqlStatementDeleteCompleted = SQL_STATEMENT_DELETE_COMPLETED.formatted(completedTable); this.sqlStatementDeleteCompletedBefore = SQL_STATEMENT_DELETE_COMPLETED_BEFORE.formatted(completedTable); - this.sqlStatementCopyToArchive = SQL_STATEMENT_COPY_TO_ARCHIVE_BY_ID.formatted(completedTable, table, completedTable); - this.sqlStatementCopyToArchiveByEventAndListenerId = SQL_STATEMENT_COPY_TO_ARCHIVE_BY_EVENT_AND_LISTENER_ID.formatted(completedTable, table, completedTable); + this.sqlStatementCopyToArchive = SQL_STATEMENT_COPY_TO_ARCHIVE_BY_ID.formatted(completedTable, table, + completedTable); + this.sqlStatementCopyToArchiveByEventAndListenerId = SQL_STATEMENT_COPY_TO_ARCHIVE_BY_EVENT_AND_LISTENER_ID + .formatted(completedTable, table, completedTable); } /* @@ -342,9 +344,11 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean @Override @Transactional(readOnly = true) - @SuppressWarnings("null") public List findIncompletePublications() { - return operations.query(sqlStatementFindUncompleted, this::resultSetToPublications); + + var result = operations.query(sqlStatementFindUncompleted, this::resultSetToPublications); + + return result == null ? Collections.emptyList() : result; } /* @@ -428,8 +432,7 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean * @return can be {@literal null}. * @throws SQLException */ - @Nullable - private TargetEventPublication resultSetToPublication(ResultSet rs) throws SQLException { + private @Nullable TargetEventPublication resultSetToPublication(ResultSet rs) throws SQLException { var id = getUuidFromResultSet(rs); var eventClass = loadClass(id, rs.getString("EVENT_TYPE")); @@ -456,8 +459,7 @@ class JdbcEventPublicationRepository implements EventPublicationRepository, Bean return settings.getDatabaseType().databaseToUUID(rs.getObject("ID")); } - @Nullable - private Class loadClass(UUID id, String className) { + private @Nullable Class loadClass(UUID id, String className) { try { return ClassUtils.forName(className, classLoader); diff --git a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcRepositorySettings.java b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcRepositorySettings.java index ceae1e8e..6d85b43a 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcRepositorySettings.java +++ b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcRepositorySettings.java @@ -15,7 +15,7 @@ */ package org.springframework.modulith.events.jdbc; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.events.support.CompletionMode; import org.springframework.util.Assert; @@ -29,7 +29,7 @@ import org.springframework.util.Assert; public class JdbcRepositorySettings { private final DatabaseType databaseType; - private final String schema; + private final @Nullable String schema; private final CompletionMode completionMode; /** @@ -67,8 +67,7 @@ public class JdbcRepositorySettings { * * @return can be {@literal null}. */ - @Nullable - public String getSchema() { + public @Nullable String getSchema() { return schema; } @@ -82,10 +81,14 @@ public class JdbcRepositorySettings { /** * Returns whether we use the archiving completion mode. */ - public boolean isArchiveCompletion() { return completionMode == CompletionMode.ARCHIVE; } + public boolean isArchiveCompletion() { + return completionMode == CompletionMode.ARCHIVE; + } /** * Returns whether we use the updating completion mode. */ - public boolean isUpdateCompletion() { return completionMode == CompletionMode.UPDATE; } + public boolean isUpdateCompletion() { + return completionMode == CompletionMode.UPDATE; + } } diff --git a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/package-info.java b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/package-info.java index 7250810c..20893d0a 100644 --- a/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/package-info.java +++ b/spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/package-info.java @@ -1,5 +1,5 @@ /** * JDBC integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.jdbc; diff --git a/spring-modulith-events/spring-modulith-events-jms/pom.xml b/spring-modulith-events/spring-modulith-events-jms/pom.xml index 735dbd46..2812b1ac 100644 --- a/spring-modulith-events/spring-modulith-events-jms/pom.xml +++ b/spring-modulith-events/spring-modulith-events-jms/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-api diff --git a/spring-modulith-events/spring-modulith-events-jms/src/main/java/org/springframework/modulith/events/jms/package-info.java b/spring-modulith-events/spring-modulith-events-jms/src/main/java/org/springframework/modulith/events/jms/package-info.java index 5c446ada..55d73d0d 100644 --- a/spring-modulith-events/spring-modulith-events-jms/src/main/java/org/springframework/modulith/events/jms/package-info.java +++ b/spring-modulith-events/spring-modulith-events-jms/src/main/java/org/springframework/modulith/events/jms/package-info.java @@ -1,5 +1,5 @@ /** * JMS event externalization support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.jms; diff --git a/spring-modulith-events/spring-modulith-events-jpa/pom.xml b/spring-modulith-events/spring-modulith-events-jpa/pom.xml index 3e6f9dcd..3edacd60 100644 --- a/spring-modulith-events/spring-modulith-events-jpa/pom.xml +++ b/spring-modulith-events/spring-modulith-events-jpa/pom.xml @@ -18,6 +18,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-events-core diff --git a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublication.java b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublication.java index 20814161..5a2b58dc 100644 --- a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublication.java +++ b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublication.java @@ -23,6 +23,8 @@ import java.time.Instant; import java.util.Objects; import java.util.UUID; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.events.jpa.archiving.ArchivedJpaEventPublication; import org.springframework.modulith.events.jpa.updating.DefaultJpaEventPublication; import org.springframework.modulith.events.support.CompletionMode; @@ -45,7 +47,7 @@ public abstract class JpaEventPublication { final String serializedEvent; final Class eventType; - protected Instant completionDate; + protected @Nullable Instant completionDate; /** * Creates a new {@link JpaEventPublication} for the given publication date, listener id, serialized event and event @@ -72,6 +74,7 @@ public abstract class JpaEventPublication { this.eventType = eventType; } + @NullUnmarked protected JpaEventPublication() { this.id = null; diff --git a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublicationRepository.java b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublicationRepository.java index 81c858fc..d6657765 100644 --- a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublicationRepository.java +++ b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/JpaEventPublicationRepository.java @@ -24,6 +24,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.IntStream; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.events.core.EventPublicationRepository; import org.springframework.modulith.events.core.EventSerializer; import org.springframework.modulith.events.core.PublicationTargetIdentifier; @@ -383,7 +384,7 @@ class JpaEventPublicationRepository implements EventPublicationRepository { private final JpaEventPublication publication; private final EventSerializer serializer; - private Object deserializedEvent; + private @Nullable Object deserializedEvent; /** * Creates a new {@link JpaEventPublicationAdapter} for the given {@link JpaEventPublication} and diff --git a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/archiving/package-info.java b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/archiving/package-info.java new file mode 100644 index 00000000..2e82f725 --- /dev/null +++ b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/archiving/package-info.java @@ -0,0 +1,5 @@ +/** + * JPA integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. + */ +@org.jspecify.annotations.NullMarked +package org.springframework.modulith.events.jpa.archiving; diff --git a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/package-info.java b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/package-info.java index 07e40cae..8a776a64 100644 --- a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/package-info.java +++ b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/package-info.java @@ -1,5 +1,5 @@ /** * JPA integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.jpa; diff --git a/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/updating/package-info.java b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/updating/package-info.java new file mode 100644 index 00000000..c1ba31b3 --- /dev/null +++ b/spring-modulith-events/spring-modulith-events-jpa/src/main/java/org/springframework/modulith/events/jpa/updating/package-info.java @@ -0,0 +1,5 @@ +/** + * JPA integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. + */ +@org.jspecify.annotations.NullMarked +package org.springframework.modulith.events.jpa.updating; diff --git a/spring-modulith-events/spring-modulith-events-kafka/pom.xml b/spring-modulith-events/spring-modulith-events-kafka/pom.xml index 02cd1cde..1fd4e9ca 100644 --- a/spring-modulith-events/spring-modulith-events-kafka/pom.xml +++ b/spring-modulith-events/spring-modulith-events-kafka/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-api diff --git a/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfiguration.java b/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfiguration.java index 250e9c2e..85f423e8 100644 --- a/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfiguration.java +++ b/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfiguration.java @@ -15,6 +15,7 @@ */ package org.springframework.modulith.events.kafka; +import org.jspecify.annotations.NullUnmarked; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.BeanFactory; @@ -53,6 +54,7 @@ class KafkaEventExternalizerConfiguration { private static final Logger logger = LoggerFactory.getLogger(KafkaEventExternalizerConfiguration.class); @Bean + @NullUnmarked DelegatingEventExternalizer kafkaEventExternalizer(EventExternalizationConfiguration configuration, KafkaOperations operations, BeanFactory factory) { diff --git a/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/package-info.java b/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/package-info.java index 6e3bdde9..eb4ce857 100644 --- a/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/package-info.java +++ b/spring-modulith-events/spring-modulith-events-kafka/src/main/java/org/springframework/modulith/events/kafka/package-info.java @@ -1,5 +1,5 @@ /** * Kafka event externalization support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.kafka; diff --git a/spring-modulith-events/spring-modulith-events-kafka/src/test/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfigurationIntegrationTests.java b/spring-modulith-events/spring-modulith-events-kafka/src/test/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfigurationIntegrationTests.java index 28f87057..cfd8caf5 100644 --- a/spring-modulith-events/spring-modulith-events-kafka/src/test/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfigurationIntegrationTests.java +++ b/spring-modulith-events/spring-modulith-events-kafka/src/test/java/org/springframework/modulith/events/kafka/KafkaEventExternalizerConfigurationIntegrationTests.java @@ -22,12 +22,12 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.kafka.core.KafkaOperations; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.modulith.events.EventExternalizationConfiguration; diff --git a/spring-modulith-events/spring-modulith-events-messaging/pom.xml b/spring-modulith-events/spring-modulith-events-messaging/pom.xml index 60ec0760..e100a2e7 100644 --- a/spring-modulith-events/spring-modulith-events-messaging/pom.xml +++ b/spring-modulith-events/spring-modulith-events-messaging/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-api diff --git a/spring-modulith-events/spring-modulith-events-messaging/src/main/java/org/springframework/modulith/events/messaging/package-info.java b/spring-modulith-events/spring-modulith-events-messaging/src/main/java/org/springframework/modulith/events/messaging/package-info.java index 54c69e5a..872954eb 100644 --- a/spring-modulith-events/spring-modulith-events-messaging/src/main/java/org/springframework/modulith/events/messaging/package-info.java +++ b/spring-modulith-events/spring-modulith-events-messaging/src/main/java/org/springframework/modulith/events/messaging/package-info.java @@ -1,5 +1,5 @@ /** * Messaging event externalization support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.messaging; diff --git a/spring-modulith-events/spring-modulith-events-mongodb/pom.xml b/spring-modulith-events/spring-modulith-events-mongodb/pom.xml index 76610621..41424b9a 100644 --- a/spring-modulith-events/spring-modulith-events-mongodb/pom.xml +++ b/spring-modulith-events/spring-modulith-events-mongodb/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-events-core @@ -26,6 +31,7 @@ org.springframework.data spring-data-mongodb + 5.0.0-SNAPSHOT diff --git a/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/MongoDbEventPublication.java b/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/MongoDbEventPublication.java index 1e89615a..e8c511f9 100644 --- a/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/MongoDbEventPublication.java +++ b/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/MongoDbEventPublication.java @@ -18,9 +18,9 @@ package org.springframework.modulith.events.mongodb; import java.time.Instant; import java.util.UUID; +import org.jspecify.annotations.Nullable; import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.mongodb.core.mapping.Document; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -85,7 +85,6 @@ class MongoDbEventPublication { MongoDbEventPublication markCompleted(Instant instant) { Assert.notNull(instant, "Instant must not be null!"); - this.completionDate = instant; return this; } diff --git a/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/package-info.java b/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/package-info.java index 7cf4668c..2b3f2811 100644 --- a/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/package-info.java +++ b/spring-modulith-events/spring-modulith-events-mongodb/src/main/java/org/springframework/modulith/events/mongodb/package-info.java @@ -1,5 +1,5 @@ /** * MongoDB integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.mongodb; diff --git a/spring-modulith-events/spring-modulith-events-neo4j/pom.xml b/spring-modulith-events/spring-modulith-events-neo4j/pom.xml index 53259b50..c72a1a8c 100644 --- a/spring-modulith-events/spring-modulith-events-neo4j/pom.xml +++ b/spring-modulith-events/spring-modulith-events-neo4j/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-events-core @@ -59,4 +64,5 @@ + diff --git a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublication.java b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublication.java index 85fcf355..16e74e00 100644 --- a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublication.java +++ b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublication.java @@ -18,7 +18,7 @@ package org.springframework.modulith.events.neo4j; import java.time.Instant; import java.util.UUID; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * The event publication entity definition. diff --git a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublicationRepository.java b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublicationRepository.java index 4726b2d1..f63fc5e8 100644 --- a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublicationRepository.java +++ b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/Neo4jEventPublicationRepository.java @@ -29,6 +29,7 @@ import java.util.UUID; import java.util.function.BiFunction; import java.util.function.Function; +import org.jspecify.annotations.Nullable; import org.neo4j.cypherdsl.core.Cypher; import org.neo4j.cypherdsl.core.Node; import org.neo4j.cypherdsl.core.ResultStatement; @@ -40,7 +41,6 @@ import org.neo4j.driver.Values; import org.neo4j.driver.types.TypeSystem; import org.springframework.data.neo4j.core.Neo4jClient; import org.springframework.data.util.Lazy; -import org.springframework.lang.Nullable; import org.springframework.modulith.events.core.EventPublicationRepository; import org.springframework.modulith.events.core.EventSerializer; import org.springframework.modulith.events.core.PublicationTargetIdentifier; diff --git a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/package-info.java b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/package-info.java index f4fec4fc..c39eac92 100644 --- a/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/package-info.java +++ b/spring-modulith-events/spring-modulith-events-neo4j/src/main/java/org/springframework/modulith/events/neo4j/package-info.java @@ -1,5 +1,5 @@ /** * Neo4j integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.events.neo4j; diff --git a/spring-modulith-examples/pom.xml b/spring-modulith-examples/pom.xml index 86676990..88f68d7a 100644 --- a/spring-modulith-examples/pom.xml +++ b/spring-modulith-examples/pom.xml @@ -118,6 +118,11 @@ + + org.jspecify + jspecify + + org.springframework.boot spring-boot-starter diff --git a/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/inventory/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/inventory/package-info.java index bf3e64df..e4ed115f 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/inventory/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/inventory/package-info.java @@ -4,5 +4,5 @@ * * @see example.inventory.InventoryInternal */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.inventory; diff --git a/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/order/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/order/package-info.java index 376d865b..62bc46dc 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/order/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-jdbc/src/main/java/example/order/package-info.java @@ -4,5 +4,5 @@ * * @see example.ModularityTests */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.order; diff --git a/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/inventory/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/inventory/package-info.java index bf3e64df..e4ed115f 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/inventory/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/inventory/package-info.java @@ -4,5 +4,5 @@ * * @see example.inventory.InventoryInternal */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.inventory; diff --git a/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/order/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/order/package-info.java index 376d865b..62bc46dc 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/order/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-mongodb/src/main/java/example/order/package-info.java @@ -4,5 +4,5 @@ * * @see example.ModularityTests */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.order; diff --git a/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/inventory/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/inventory/package-info.java index bf3e64df..e4ed115f 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/inventory/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/inventory/package-info.java @@ -4,5 +4,5 @@ * * @see example.inventory.InventoryInternal */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.inventory; diff --git a/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/order/package-info.java b/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/order/package-info.java index 376d865b..62bc46dc 100644 --- a/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/order/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-epr-neo4j/src/main/java/example/order/package-info.java @@ -4,5 +4,5 @@ * * @see example.ModularityTests */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.order; diff --git a/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/inventory/package-info.java b/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/inventory/package-info.java index bf3e64df..e4ed115f 100644 --- a/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/inventory/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/inventory/package-info.java @@ -4,5 +4,5 @@ * * @see example.inventory.InventoryInternal */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.inventory; diff --git a/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/order/package-info.java b/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/order/package-info.java index 376d865b..62bc46dc 100644 --- a/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/order/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-full/src/main/java/example/order/package-info.java @@ -4,5 +4,5 @@ * * @see example.ModularityTests */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.order; diff --git a/spring-modulith-examples/spring-modulith-example-kafka/src/main/java/example/order/package-info.java b/spring-modulith-examples/spring-modulith-example-kafka/src/main/java/example/order/package-info.java index 376d865b..62bc46dc 100644 --- a/spring-modulith-examples/spring-modulith-example-kafka/src/main/java/example/order/package-info.java +++ b/spring-modulith-examples/spring-modulith-example-kafka/src/main/java/example/order/package-info.java @@ -4,5 +4,5 @@ * * @see example.ModularityTests */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package example.order; diff --git a/spring-modulith-integration-test/pom.xml b/spring-modulith-integration-test/pom.xml index 9434d7ea..976d3d67 100644 --- a/spring-modulith-integration-test/pom.xml +++ b/spring-modulith-integration-test/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-core diff --git a/spring-modulith-junit/pom.xml b/spring-modulith-junit/pom.xml index a6ca1cfc..04d53588 100644 --- a/spring-modulith-junit/pom.xml +++ b/spring-modulith-junit/pom.xml @@ -17,6 +17,10 @@ + + org.jspecify + jspecify + org.eclipse.jgit org.eclipse.jgit @@ -51,5 +55,4 @@ - diff --git a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/ModulithExecutionCondition.java b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/ModulithExecutionCondition.java index 54cd3253..7dde4763 100644 --- a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/ModulithExecutionCondition.java +++ b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/ModulithExecutionCondition.java @@ -20,10 +20,10 @@ import java.util.Collection; import java.util.Set; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; import org.junit.jupiter.api.extension.ExtensionContext; -import org.springframework.lang.Nullable; import org.springframework.modulith.junit.TestExecutionCondition.ConditionContext; /** diff --git a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/FileModificationDetector.java b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/FileModificationDetector.java index c929fc01..2d9f347f 100644 --- a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/FileModificationDetector.java +++ b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/FileModificationDetector.java @@ -17,11 +17,11 @@ package org.springframework.modulith.junit.diff; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.core.env.PropertyResolver; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; diff --git a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/ReferenceCommitDetector.java b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/ReferenceCommitDetector.java index 7f5f5e21..c063b5d9 100644 --- a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/ReferenceCommitDetector.java +++ b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/diff/ReferenceCommitDetector.java @@ -19,10 +19,10 @@ import static org.springframework.modulith.junit.diff.JGitUtil.*; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.PropertyResolver; -import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** diff --git a/spring-modulith-moments/pom.xml b/spring-modulith-moments/pom.xml index 530d283e..d63b5fbb 100644 --- a/spring-modulith-moments/pom.xml +++ b/spring-modulith-moments/pom.xml @@ -16,6 +16,11 @@ + + org.jspecify + jspecify + + org.jmolecules jmolecules-events @@ -41,4 +46,4 @@ - \ No newline at end of file + diff --git a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/autoconfigure/package-info.java b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/autoconfigure/package-info.java index b9b41da6..afe980a0 100644 --- a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/autoconfigure/package-info.java +++ b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/autoconfigure/package-info.java @@ -1,5 +1,5 @@ /** * Autoconfiguration for the {@link org.springframework.modulith.moments.support.Moments} API. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.moments.autoconfigure; diff --git a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/package-info.java b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/package-info.java index 9ee45940..9fabf78e 100644 --- a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/package-info.java +++ b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/package-info.java @@ -1,5 +1,5 @@ /** * An Passage-of-Time events implementation. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.moments; diff --git a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/MomentsProperties.java b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/MomentsProperties.java index 8ed83de7..9f0586d4 100644 --- a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/MomentsProperties.java +++ b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/MomentsProperties.java @@ -23,10 +23,10 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.ConstructorBinding; import org.springframework.boot.context.properties.bind.DefaultValue; -import org.springframework.lang.Nullable; import org.springframework.modulith.moments.Quarter; import org.springframework.modulith.moments.ShiftedQuarter; import org.springframework.util.Assert; diff --git a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/package-info.java b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/package-info.java index 31478239..a60f82e4 100644 --- a/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/package-info.java +++ b/spring-modulith-moments/src/main/java/org/springframework/modulith/moments/support/package-info.java @@ -2,5 +2,5 @@ * The {@link org.springframework.modulith.moments.support.Moments} abstraction to integrate with Spring Framework's * scheduling. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.moments.support; diff --git a/spring-modulith-observability/pom.xml b/spring-modulith-observability/pom.xml index efe1dc50..f6985716 100644 --- a/spring-modulith-observability/pom.xml +++ b/spring-modulith-observability/pom.xml @@ -22,6 +22,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-core diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/package-info.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/package-info.java index 11a576ba..52fac7c8 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/package-info.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/package-info.java @@ -1,5 +1,5 @@ /** * Autoconfiguration for the observability integration. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.observability.autoconfigure; diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/package-info.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/package-info.java index 83662785..f15d6753 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/package-info.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/package-info.java @@ -1,5 +1,5 @@ /** * Support for application module observability. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.observability; diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/DefaultObservedModule.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/DefaultObservedModule.java index 261acc33..fd7dde9e 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/DefaultObservedModule.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/DefaultObservedModule.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.aop.ProxyMethodInvocation; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; @@ -111,9 +112,9 @@ class DefaultObservedModule implements ObservedModule { /* * (non-Javadoc) - * @see org.springframework.modulith.observability.ObservedModule#getInterceptionConfiguration(java.lang.Class, org.springframework.modulith.model.Modules) + * @see org.springframework.modulith.observability.support.ObservedModule#getObservedModuleType(java.lang.Class, org.springframework.modulith.core.ApplicationModules) */ - public ObservedModuleType getObservedModuleType(Class type, ApplicationModules modules) { + public @Nullable ObservedModuleType getObservedModuleType(Class type, ApplicationModules modules) { Assert.notNull(type, "Type must not be null!"); Assert.notNull(modules, "ApplicationModules must not be null!"); @@ -161,7 +162,7 @@ class DefaultObservedModule implements ObservedModule { var advised = (Advised) ((ProxyMethodInvocation) invocation).getProxy(); var targetClass = advised.getTargetClass(); - if (module.contains(targetClass)) { + if (targetClass != null && module.contains(targetClass)) { return AopUtils.getMostSpecificMethod(method, targetClass); } diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleEntryInterceptor.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleEntryInterceptor.java index 1a03d6c1..86b67d1e 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleEntryInterceptor.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleEntryInterceptor.java @@ -25,10 +25,10 @@ import java.util.Objects; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; -import org.springframework.lang.Nullable; import org.springframework.modulith.core.ApplicationModuleIdentifier; import org.springframework.modulith.observability.support.ModulithObservations.LowKeys; import org.springframework.util.Assert; @@ -69,11 +69,11 @@ class ModuleEntryInterceptor implements MethodInterceptor { * * @param module must not be {@literal null}. * @param observationRegistry must not be {@literal null}. - * @param custom must not be {@literal null}. + * @param custom can be {@literal null}. * @param environment must not be {@literal null}. */ private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observationRegistry, - ModulithObservationConvention custom, Environment environment) { + @Nullable ModulithObservationConvention custom, Environment environment) { Assert.notNull(module, "ObservedModule must not be null!"); Assert.notNull(observationRegistry, "ObservationRegistry must not be null!"); @@ -90,7 +90,7 @@ class ModuleEntryInterceptor implements MethodInterceptor { } public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry, - ModulithObservationConvention custom, Environment environment) { + @Nullable ModulithObservationConvention custom, Environment environment) { return CACHE.computeIfAbsent(module.getIdentifier(), __ -> { return new ModuleEntryInterceptor(module, observationRegistry, custom, environment); @@ -102,7 +102,7 @@ class ModuleEntryInterceptor implements MethodInterceptor { * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { var moduleIdentifier = module.getIdentifier(); var currentObservation = observationRegistry.getCurrentObservation(); diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleObservabilitySupport.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleObservabilitySupport.java index f9fc9495..a24919a6 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleObservabilitySupport.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModuleObservabilitySupport.java @@ -17,6 +17,7 @@ package org.springframework.modulith.observability.support; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.springframework.aop.Advisor; import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyFactory; @@ -24,7 +25,6 @@ import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.lang.Nullable; import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor; /** diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModulithContext.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModulithContext.java index 96912394..174c3732 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModulithContext.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ModulithContext.java @@ -18,6 +18,7 @@ package org.springframework.modulith.observability.support; import io.micrometer.observation.Observation.Context; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.core.env.Environment; import org.springframework.util.Assert; @@ -32,7 +33,7 @@ public class ModulithContext extends Context { private final ObservedModule module; private final MethodInvocation invocation; - private final String applicationName; + private final @Nullable String applicationName; /** * Creates a new {@link ModulithContext} for the given {@link ObservedModule}, {@link MethodInvocation} and @@ -61,7 +62,7 @@ public class ModulithContext extends Context { return invocation; } - public String getApplicationName() { + public @Nullable String getApplicationName() { return applicationName; } } diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ObservedModule.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ObservedModule.java index f5e4c42d..74fbcec1 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ObservedModule.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/ObservedModule.java @@ -18,7 +18,7 @@ package org.springframework.modulith.observability.support; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInvocation; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModuleIdentifier; import org.springframework.modulith.core.ApplicationModules; diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/SpringDataRestModuleObservabilityBeanPostProcessor.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/SpringDataRestModuleObservabilityBeanPostProcessor.java index 2e991146..650e7ad0 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/SpringDataRestModuleObservabilityBeanPostProcessor.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/SpringDataRestModuleObservabilityBeanPostProcessor.java @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -28,7 +29,6 @@ import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.env.Environment; import org.springframework.data.rest.webmvc.BasePathAwareController; import org.springframework.data.rest.webmvc.RootResourceInformation; -import org.springframework.lang.Nullable; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModules; import org.springframework.modulith.runtime.ApplicationModulesRuntime; @@ -114,7 +114,7 @@ public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleOb * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { var module = getModuleFrom(invocation.getArguments()); diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/package-info.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/package-info.java index dcfe3c45..2c76f808 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/package-info.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/support/package-info.java @@ -1,5 +1,5 @@ /** * Support for application module observability. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.observability.support; diff --git a/spring-modulith-runtime/pom.xml b/spring-modulith-runtime/pom.xml index eb9d6169..98e58615 100644 --- a/spring-modulith-runtime/pom.xml +++ b/spring-modulith-runtime/pom.xml @@ -16,6 +16,11 @@ + + org.jspecify + jspecify + + org.springframework.modulith spring-modulith-core diff --git a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/ApplicationRuntime.java b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/ApplicationRuntime.java index 801d8858..29120994 100644 --- a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/ApplicationRuntime.java +++ b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/ApplicationRuntime.java @@ -15,6 +15,7 @@ */ package org.springframework.modulith.runtime; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; @@ -44,6 +45,7 @@ public interface ApplicationRuntime { * * @return will never be {@literal null}. */ + @Nullable String getId(); /** diff --git a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/SpringBootApplicationRuntime.java b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/SpringBootApplicationRuntime.java index 4eaefad0..d7fff087 100644 --- a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/SpringBootApplicationRuntime.java +++ b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/SpringBootApplicationRuntime.java @@ -18,8 +18,10 @@ package org.springframework.modulith.runtime; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @@ -37,8 +39,8 @@ class SpringBootApplicationRuntime implements ApplicationRuntime { private static final Map APPLICATION_CLASSES = new ConcurrentHashMap<>(); private final ApplicationContext context; - private Class mainApplicationClass; - private List resolvedAutoConfigurationPackages; + private @Nullable Class mainApplicationClass; + private @Nullable List resolvedAutoConfigurationPackages; /** * Creates a new {@link SpringBootApplicationRuntime} for the given {@link ApplicationContext}. @@ -57,7 +59,7 @@ class SpringBootApplicationRuntime implements ApplicationRuntime { * @see org.springframework.modulith.observability.ApplicationRuntime#getId() */ @Override - public String getId() { + public @Nullable String getId() { return context.getId(); } @@ -92,7 +94,7 @@ class SpringBootApplicationRuntime implements ApplicationRuntime { ? context.getType(beanName) : bean.getClass(); - return ClassUtils.getUserClass(beanType); + return ClassUtils.getUserClass(Objects.requireNonNull(beanType)); } /* diff --git a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/package-info.java b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/package-info.java index a118e8bb..8a78276a 100644 --- a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/package-info.java +++ b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/package-info.java @@ -1,5 +1,5 @@ /** * Autoconfiguration the {@link org.springframework.modulith.core.ApplicationModules} runtime support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.runtime.autoconfigure; diff --git a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/package-info.java b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/package-info.java index aef0b465..5ef75976 100644 --- a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/package-info.java +++ b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/package-info.java @@ -1,5 +1,5 @@ /** * Support to run {@link org.springframework.modulith.core.ApplicationModules} at application runtime. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.modulith.runtime; diff --git a/spring-modulith-test/pom.xml b/spring-modulith-test/pom.xml index efa4847a..5dc22ef1 100644 --- a/spring-modulith-test/pom.xml +++ b/spring-modulith-test/pom.xml @@ -17,6 +17,11 @@ + + org.jspecify + jspecify + + ${project.groupId} spring-modulith-core @@ -67,4 +72,5 @@ + diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/AggregateTestUtils.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/AggregateTestUtils.java index b0828284..b73aabe2 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/AggregateTestUtils.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/AggregateTestUtils.java @@ -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) diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/DefaultPublishedEvents.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/DefaultPublishedEvents.java index d4b3493d..5bc53865 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/DefaultPublishedEvents.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/DefaultPublishedEvents.java @@ -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 TypedPublishedEvents matching(Function mapper, S value) { + public TypedPublishedEvents matching(Function mapper, @Nullable S value) { return matching(mapper, (Predicate) it -> Objects.equals(it, value)); } diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java index ec331dc8..cb443d9a 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java @@ -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 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)); diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleTestExecution.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleTestExecution.java index b71a1333..e203f8f0 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleTestExecution.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleTestExecution.java @@ -109,15 +109,21 @@ public class ModuleTestExecution implements Iterable { 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)); diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEvents.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEvents.java index 95134f56..43b38fe5 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEvents.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEvents.java @@ -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; /** diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsAssert.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsAssert.java index 67ee016c..32b872d3 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsAssert.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsAssert.java @@ -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; diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java index a7c964bc..d044d763 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java @@ -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 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; } diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/Scenario.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/Scenario.java index 1ff8d032..0a741854 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/Scenario.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/Scenario.java @@ -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 type; private final Function, TypedPublishedEvents> filter; - private final ExecutionResult previousResult; + private final @Nullable ExecutionResult 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 type, Function, TypedPublishedEvents> filtered, - ExecutionResult previousResult) { + @Nullable ExecutionResult previousResult) { Assert.notNull(type, "Event type must not be null!"); diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/package-info.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/package-info.java index 89293ebe..af2959d2 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/package-info.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/package-info.java @@ -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; diff --git a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ScenarioCustomizerIntegrationTests.java b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ScenarioCustomizerIntegrationTests.java index 455a69c8..b78b7ee5 100644 --- a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ScenarioCustomizerIntegrationTests.java +++ b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ScenarioCustomizerIntegrationTests.java @@ -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