We now resort to a simple iteration over the types within a Classes arrangement to detect all classes residing in certain packages. This is primarily used during the JavaPackage data structure construction as it's called for every sub-package of a package originally created from a Classes instance. The new simplified algorithm avoids set up of DescribedPredicate instances to eventually only perform simple package name checks.
This is to make sure that marker types annotated with @PackageInfo are considered, too. Deprecate JavaPackage.getAnnotation(…) as it's not used anywhere anymore and we would like to consistently consider package info marker types when looking up package annotations.
Before this commit, ApplicationModuleSource inspected all package-info.java contained in given packages, including the sub-packages of those. That caused identifiers explicitly defined in an @ApplicationModule on a package-info.java in nested packages picked up for top-level packages. This is now fixed by only considering the files in the top-level packages.
We now detect event types a listener is interested in declared in annotations for inclusion the reference documentation. This allows for the rare case that the event listener method not actually declaring the event type as parameter as it might not be needed in the payload but only the fact that an event was published at all.
We now properly translate jMolecules' @Module declaration configuring the id attribute explicitly into the identifier used for an application module.
Introduce @ApplicationModule(id = …) for Spring Modulith-native identifier customization.
Introduced ApplicationModuleIdentifier that ensures that identifiers chosen for application modules do not contain a double colon (::) as we need those as separator characters for manual dependency declarations referring to named interfaces.
ApplicationModule now exposes both getDirectDependencies(…) and getAllDependencies(…), the former as alias for the now deprecated getDependencies(…) for symmetry reasons. The latter recursively resolves transitive dependencies.
We now optimize the dependency analysis by skipping types residing java and javax packages as they're not relevant to our dependency arrangement model. A few additional optimizations in ApplicationModuleDependencies to avoid iterating over each establishing dependency if all we need to look at is the general module dependency arrangement.
Improve performance of ApplicationModule.contains(…) checks by checking whether the given type can even live inside the package space of the module.
We now expose ApplicationModuleSourceFactory as Spring Factories-based SPI interface to further contribute ApplicationModuleSource instances either from a provided root package subject for module detection through a (potentially customized) ApplicationModuleDetectionStrategy or by explicitly listing particular module base packages.
The ApplicationModules bootstrap now triggers the module base package detection, followed by a new, additional pass of detecting nested application module packages. Those packages are now added to the ones we create ApplicationModule instances for and also handed into the module instance creation step as exclusions to make sure that parent modules do not include code residing in sub-modules.
The bootstrap of ApplicationModules now uses a dedicated ApplicationModuleSource to allow calculating a default module name relative to the application base package.
Each module now operates on the Classes instance obtained from the JavaPackage instance that constitutes the module's base package but filtered by the given exclusions.
If named interfaces are declared in nested packages, the name detection might accidentally pick up the names declared in child packages. We now deliberately only inspect the base package.
As we process a type's entire type hierarchy for dependencies we might discover a foreign module's internal dependencies for modules that declare allowed dependencies explicitly. Explicitly declared dependencies so far solely verified the target being explicitly listed, which, for internal dependencies does not make sense. We now immediately start checking the source and target modules to be equivalent, in which case we can skip any further processing.
We now expose a configuration property spring.modulith.detection-strategy that can take either of the two prepared values "direct-sub-packages" (default) or "explicitly-annotated", or a fully qualified class name of the strategy to use.
Removed ApplicationModuleStrategies enum to avoid exposing the enum values as additional implementations. Those are now held as inline lambda expression in the factory methods on ApplicationModuleStrategy. Extracted the lookup of the strategy to use into ApplicationModuleDetectionStrategyLookup for easier testability.
Previously, we had a variety of places calculating the overall packages to inspect for types. This is now all consolidated into the ModulithMetadata abstraction exposing them directly.
When defining allowed application module dependencies to named interfaces, the asterisk can now be used to allow referencing all named interfaces declared by the target module.
Introduce @PackageInfo annotation to allow marking a types as alternative to Java's native package-info.java so that annotation lookups on a JavaPackage will also find annotations placed on that type. Useful to declare package scoped metadata like @ApplicationModule and @NamedInterface for languages that do not support packages well enough (read: Kotlin).
Removed the inclusion of the spring-modulith-runtime artifact from the …-starter-core one to avoid issues in native images in a Spring Modulith default setup. As the artifact is still needed to support ApplicationModuleInitializer implementations, we now explicitly check for the presence of those and verify the artifact is actually available and hint the user at explicitly adding it if missing.
Prior to this commit, the lookup for an ApplicationModule would find modules solely depending on the reference string starting with the base package. That means that a module with base package com.acme.foo, a request for com.acme.foobar would've resulted in a positive match, which of course is wrong.
We now match against either the module's base package or against the reference starting with the base package followed by a dot.
We now properly check whether one of a Spring bean's implemented interfaces is exposed by the module before including it in the default rendering of the Application Module Canvas.
Type based named interfaces on types declared in a module's API package still caused the type to be included in the unnamed interface. This is now fixed by explicitly removing named interface types from the unnamed interface.
We now also detect API package types assigned to a named interface without an explicit name as the package name defaulting doesn't work in this case.
Furthermore, named interfaces are now sorted alphabetically to make the unnamed one always appear first.
Both package- and type-level declarations now use the local package name as the named interface's name. This allows to, at the same time, easily declared named interfaces based on packages but also a nice decoupling of the interface definition and the package layout as individual types can be assigned to such interfaces no matter where they are actually declared.
Introduce Spring Modulith Actuator module to expose the application module structure as Spring Boot actuator. This required a Spring Modulith Runtime module to be extracted from the Spring Modulith Observability one. The former now contains the auto-configured ApplicationRuntime and ApplicationModulesRuntime bean instances to be able to bootstrap a ApplicationModules asynchronously on application startup. The actuator module then contains a Spring Boot @Endpoint implementation consuming the ApplicationModules to render JSON describing the application module structure.
Overhauled the module canvas in various ways. By default, we now skip "empty" rows. In other words, if we do not find any published events for example, we skip the entire row. CanvasOptions.revealEmptyRows() can be used to keep those empty rows around. We now also expose all value types and Spring bean references.
Refactored the dependency lookup APIs on ApplicationModule. Both DependencyType and DependencyDepth are now top-level types. Also, ApplicationModuleDependency and ApplicationModuleDependencies were introduced as explicit types. In the course of that, ApplicationModule.getDependencies(…) has got its return type changed from List<ApplicationModule> to ApplicationModuleDependencies. The internal ModuleDependency type has been renamed to QualifiedDependency.
Upgrade to Spring Boot 3 and Java 17 as project baselines. Removed legacy JavaEE modules and replaced them by ones compatible with JakartaEE 9.
Disabled the Observability module for now as Spring Cloud Sleuth has been removed the Boot 3 compatible Spring Cloud branch and we need to migrate the module to Micrometer first.