-
Notifications
You must be signed in to change notification settings - Fork 237
Spring Modulith Support
Describes the current support for Spring Modulith in the Spring Tools. Spring Modulith lets you structure a Spring Boot application into logical application modules, with each module exposing a well-defined API to the rest of the system and keeping the rest of its code internal.
The Spring Tools pick up that module structure and make it visible while you are coding:
- Application module structure in the Logical Structure view
- Validation of references to module internals
- Validation and quick fix for
@ApplicationModuleListener - Application module structure for AI assistants
All of this is enabled automatically, there is nothing to install in addition to the Spring Tools.
The tooling considers a project to be a Spring Modulith project as soon as it has a spring-modulith-core dependency on its compile or runtime classpath. A dependency that exists only for tests is not enough - the Modulith features stay switched off for such a project.
All Modulith-specific features are built on top of the application module metadata: the list of application modules of the project, their base packages, and the named interfaces that each module exposes.
The Spring Tools do not re-implement the rules that Spring Modulith uses to derive that information. Instead they run Spring Modulith's own ApplicationModulesExporter in a separate process, using the classpath of your project, starting at the package of each @SpringBootApplication class of the project. This way the tooling always sees exactly the same module structure that Spring Modulith itself sees at runtime, including everything that you configured via @ApplicationModule, @NamedInterface, or package-info.java files.
Two consequences of this approach are worth knowing about:
-
The project needs to be built. The exporter works on compiled classes, so a project without any
.classfiles in its output folders has no module metadata yet. If the module structure in the tooling looks empty or outdated, a (re-)build of the project is usually the fix. -
The metadata is cached and refreshed in the background. The tools watch the output folders of the project and re-compute the metadata when class files of module packages change -
package-info.classfiles in particular, since those carry the module and named interface declarations.
The background tracking of Modulith projects is switched on by default. You can turn it off if you prefer to update the metadata manually only:
-
Eclipse:
Preferences->Spring->Spring Boot Modulith automatic project tracking and metadata update -
VSCode: the
boot-java.modulith-project-trackingsetting
You can always ask the tooling to re-compute the module metadata of a project and re-validate its sources:
-
Eclipse: right-click the project (or its
pom.xml/build.gradlefile) and chooseSpring->Refresh Modulith Metadata. The action shows up for Maven and Gradle projects that depend onspring-modulith-core. -
VSCode: run
Spring Boot: Refresh Modulith Metadatafrom the command palette. If more than one Modulith project is open, you are asked which project to refresh.
The tooling reports back whether the metadata actually changed, and tells you when it could not be computed - for example because the project does not depend on Spring Modulith at all, or because its output folder does not contain any compiled classes yet.
The Logical Structure view shows the components of a Spring Boot project grouped by their logical role instead of by files and folders. For Spring Modulith projects, the application modules become the top level of that tree:
- Each application module appears as a node labelled with its display name followed by its (abbreviated) base package.
- Inside a module, its components are grouped by their stereotypes, in the same way as for non-Modulith projects.
- Each type is marked as either
(API)or(internal), depending on whether the module exposes it through one of its named interfaces. This makes it easy to see at a glance which parts of a module other modules are allowed to use.
You can open the view via Window -> Show View -> Spring -> Logical Structure in Eclipse, and as the Logical Structure section of the Explorer in VSCode. The refresh action of the view re-requests the Modulith metadata before rebuilding the tree, so it doubles as a quick way to pick up module changes. The grouping action lets you choose which stereotype groups the tree should be structured by.
Spring Modulith projects usually verify their module boundaries with an ApplicationModules.verify() test. The Spring Tools bring the most important part of that check directly into the editor: a type from another application module that is not exposed via one of that module's named interfaces is flagged right where it is referenced.
The problem is reported as Invalid reference to non-exposed type of module '<module>'! and has ERROR severity by default.
Consider a project with an order module that exposes its spi sub-package as a named interface:
// src/main/java/com/example/order/spi/package-info.java
@org.springframework.modulith.NamedInterface
package com.example.order.spi;Then, from within a different module:
package com.example.inventory;
import com.example.order.spi.SomeSpi; // fine, exposed via a named interface
import com.example.order.internal.OrderInternal; // flagged: not exposed by module 'order'
class InventoryManagement {
// ...
}References within the same application module are never flagged, and neither are references to types that any named interface of the target module exposes.
Note that this validation can only run once the module metadata is available, so it needs a built project just like the structure view does. Whenever the metadata changes, the tooling automatically re-validates the Java sources of the project.
(new in 5.4.0 / 2.4.0)
Spring Modulith provides @ApplicationModuleListener as a single meta-annotation for the common combination of @Async, @Transactional, and @TransactionalEventListener. In Spring Modulith projects, the tooling points out methods that still use the three separate annotations and offers a quick fix to combine them. The problem is reported with INFO severity by default.
Before:
@Async
@Transactional
@TransactionalEventListener
void on(OrderCompleted event) {
// ...
}After applying the quick fix:
@ApplicationModuleListener
void on(OrderCompleted event) {
// ...
}Two quick fixes are offered: Combine into @ApplicationModuleListener for the method at hand, and Combine all into @ApplicationModuleListener in file to convert every affected method of the file at once. Unused imports of the replaced annotations are cleaned up, and the attributes that @ApplicationModuleListener supports are carried over - @Transactional's readOnly becomes readOnlyTransaction, propagation stays propagation, and @TransactionalEventListener's id and condition are kept as they are.
Methods that use an attribute which @ApplicationModuleListener cannot express - for example @Async("executorName"), @Transactional(timeout = ...), or @TransactionalEventListener(phase = ...) - are deliberately left alone, since combining the annotations would silently change the behavior of the method.
Both Modulith validations are part of the Spring-specific validations of the tooling, so everything described in Validations and Quick Fixes applies to them as well. You can change their severity individually, or set them to IGNORE if you don't want to see them at all:
-
Eclipse:
Preferences->Spring->Validation, in theBoot 3.x Best Practices & Optimizationscategory -
VSCode: the
spring-boot.ls.problem.boot3.MODULITH_TYPE_REF_VIOLATIONandspring-boot.ls.problem.boot3.MODULITH_APPLICATION_MODULE_LISTENERsettings
Since both validations analyze Java sources, they require Reconciling of Java Sources to be enabled (which is the default).
The language server ships an embedded MCP server, and the logical structure of a project - including the application modules of Spring Modulith projects - is available to AI assistants through it. An assistant can therefore reason about your application in terms of its application modules and exposed APIs instead of just its files, and it sees exactly the same tree that the Logical Structure view renders.
- Module metadata is derived from compiled classes, so changes to module or named interface declarations only become visible to the tooling after the project has been rebuilt.
- Computing the metadata starts from the
@SpringBootApplicationclasses of a project. A Modulith project without such a class in the tooling's index does not get any module metadata.
- Installation (latest release + snapshots)
- Leyden AOT Cache
- User Guide
- FAQ
- Changelog
- Known Limitations & Issues
- Report an Issue
- Developer Manual
- Overview
- Language Server Integration into Clients
- Communication with JDT LS
- Spring Tools Language Server Protocol Extensions