[[fundamentals]]
= Fundamentals
:tabsize: 2
:toc:
:toclevels: 3

Spring Modulith supports developers implementing logical modules in Spring Boot applications.
It allows them to apply structural validation, document the module arrangement, run integration tests for individual modules, observe the modules' interaction at runtime, and generally implement module interaction in a loosely coupled way.
This section will discuss the fundamental concepts that developers need to understand before diving into the technical support.

[[modules]]
== Application Modules

In a Spring Boot application, an application module is a unit of functionality that consists of the following parts:

* An API exposed to other modules implemented by Spring bean instances and application events published by the module, usually referred to as _provided interface_.
* Internal implementation components that are not supposed to be accessed by other modules.
* References to API exposed by other modules in the form of Spring bean dependencies, application events listened to and configuration properties exposed, usually referred to as _required interface_.

Spring Moduliths provides different ways of expressing modules within Spring Boot applications, primarily differing in the level of complexity involved in the overall arrangement.
This allows developers to start simple and naturally move to more sophisticated means as and if needed.

[[modules.application-modules]]
=== The `ApplicationModules` Type

Spring Moduliths allows to inspect a codebase to derive an application module model based on the given arrangement and optional configuration.
The `spring-modulith-core` artifact contains `ApplicationModules` that can be pointed to a Spring Boot application class:

.Creating an application module model
[tabs]
======
Java::
+
[source, java, role="primary"]
----
var modules = ApplicationModules.of(Application.class);
----
Kotlin::
+
[source, kotlin, role="secondary"]
----
val modules = ApplicationModules.of(Application::class.java)
----
======
The `modules` will contain an in-memory representation of the application module arrangement derived from the codebase.
Which parts of that will be detected as a module depends on the Java package structure underneath the package the class pointed to resides in.
Find out more about the arrangement expected by default in xref:fundamentals.adoc#modules.simple[].
Advanced arrangements and customization options are described in xref:fundamentals.adoc#modules.advanced[] and

To get an impression of what the analyzed arrangement looks like, we can just write the individual modules contained in the overall model to the console:

.Writing the application module arrangement to the console
[tabs]
======
Java::
+
[source, java, role="primary"]
----
modules.forEach(System.out::println);
----
Kotlin::
+
[source, kotlin, role="secondary"]
----
modules.forEach { println(it) }
----
======
.The console output of our application module arrangement
[source]
----
## example.inventory ##
> Logical name: inventory
> Base package: example.inventory
> Spring beans:
  + ….InventoryManagement
  o ….SomeInternalComponent

## example.order ##
> Logical name: order
> Base package: example.order
> Spring beans:
  + ….OrderManagement
  + ….internal.SomeInternalComponent
----

Note how each module is listed, the contained Spring components are identified, and the respective visibility is rendered, too.

[[modules.excluding-packages]]
==== Excluding Packages

In case you would like to exclude certain Java classes or full packages from the application module inspection, you can do so with:

[tabs]
======
Java::
+
[source, java, role="primary"]
----
ApplicationModules.of(Application.class, JavaClass.Predicates.resideInAPackage("com.example.db")).verify();
----
Kotlin::
+
[source, kotlin, role="secondary"]
----
ApplicationModules.of(Application::class.java, JavaClass.Predicates.resideInAPackage("com.example.db")).verify()
----
======

Additional examples of exclusions:

* `com.example.db` -- Matches all files in the given package `com.example.db`.
* `com.example.db..` -- Matches all files in the given package (`com.example.db`) and all sub-packages (`com.example.db.a` or `com.example.db.b.c`).
* `..example..` -- Matches `a.example`, `a.example.b` or `a.b.example.c.d`, but not `a.exam.b`

Full details about possible matchers can be found in the JavaDoc of ArchUnit https://github.com/TNG/ArchUnit/blob/main/archunit/src/main/java/com/tngtech/archunit/core/domain/PackageMatcher.java[`PackageMatcher`].

[[modules.simple]]
=== Simple Application Modules

The application's _main package_ is the one that the main application class resides in.
That is the class, that is annotated with `@SpringBootApplication` and usually contains the `main(…)` method used to run it.
By default, each direct sub-package of the main package is considered an _application module package_.

If this package does not contain any sub-packages, it is considered a simple one.
It allows to hide code inside it by using Java's package scope to hide types from being referred to by code residing in other packages and thus not subject to dependency injection into those.
Thus, naturally, the module's API consists of all public types in the package.

Let us have a look at an example arrangement (icon:plus-circle[role=green] denotes a public type, icon:minus-circle[role=red] a package-private one).

.A single inventory application module
[source, subs="+specialchars, macros"]
----
icon:cubes[] Example
└─ icon:folder[] src/main/java
   ├─ icon:cube[] example                        <1>
   |  └─ icon:plus-circle[role=green] Application.java
   └─ icon:cube[] example.inventory              <2>
      ├─ icon:plus-circle[role=green] InventoryManagement.java
      └─ icon:minus-circle[role=red] SomethingInventoryInternal.java
----
<1> The application's main package `example`.
<2> An application module package `inventory`.

[[modules.advanced]]
=== Advanced Application Modules

If an application module package contains sub-packages, types in those might need to be made public so that it can be referred to from code of the very same module.

.An inventory and order application module
[source, subs="macros, quotes"]
----
icon:cubes[] Example
└─ icon:folder[] src/main/java
   ├─ icon:cube[] example
   |  └─ icon:plus-circle[role=green] Application.java
   ├─ icon:cube[] example.inventory
   |  ├─ icon:plus-circle[role=green] InventoryManagement.java
   |  └─ icon:minus-circle[role=red] SomethingInventoryInternal.java
   ├─ **icon:cube[] example.order**
   |  └─ icon:plus-circle[role=green] OrderManagement.java
   └─ icon:cube[] example.order.internal
      └─ icon:plus-circle[role=green] SomethingOrderInternal.java
----

In such an arrangement, the `order` package is considered an API package.
Code from other application modules is allowed to refer to types within that.
`order.internal`, just as any other sub-package of the application module base package, is considered an _internal_ one.
Code within those must not be referred to from other modules.
Note how `SomethingOrderInternal` is a public type, likely because `OrderManagement` depends on it.
This unfortunately means that it can also be referred to from other packages such as the `inventory` one.
In this case, the Java compiler is not of much use to prevent these illegal references.

[[modules.nested]]
=== Nested Application Modules

As of version 1.3, Spring Modulith application modules can contain nested modules.
This allows governing the internal structure in case a module contains parts to be logically separated in turn.
To define nested application modules, explicitly annotate packages that are supposed to constitute with `@ApplicationModule`.

[source, subs="macros, quotes"]
----
icon:cubes[] Example
└─ icon:folder[] src/main/java
   |
   ├─ icon:cube[] example
   |  └─ icon:plus-circle[role=green] Application.java
   |
   |  -> Inventory
   |
   ├─ icon:cube[] example.inventory
   |  ├─ icon:plus-circle[role=green] InventoryManagement.java
   |  └─ icon:minus-circle[role=red] SomethingInventoryInternal.java
   ├─ icon:cube[] example.inventory.internal
   |  └─ icon:minus-circle[role=red] SomethingInventoryInternal.java
   |
   |  -> Inventory > Nested
   |
   ├─ icon:cube[] example.inventory.nested
   |  ├─ icon:coffee[] package-info.java // @ApplicationModule
   |  └─ icon:plus-circle[role=orange] NestedApi.java
   ├─ icon:cube[] example.inventory.nested.internal
   |  └─ icon:minus-circle[role=red] NestedInternal.java
   |
   |  -> Order
   |
   └─ icon:cube[] example.order
      ├─ icon:plus-circle[role=green] OrderManagement.java
      └─ icon:minus-circle[role=red] SomethingOrderInternal.java
----

In this example `inventory` is an application module as described xref:fundamentals.adoc#modules.simple[above].
The `@ApplicationModule` annotation on the `nested` package caused that to become a nested application module in turn.
In that arrangement, the following access rules apply:

* The code in _Nested_ is only available from _Inventory_ or any types exposed by sibling application modules nested inside _Inventory_.
* Any code in the _Nested_ module can access code in parent modules, even internal.
I.e., both `NestedApi` and `NestedInternal` can access `inventory.internal.SomethingInventoryInternal`.
* Code from nested modules can also access exposed types by top-level application modules.
Any code in `nested` (or any sub-packages) can access `OrderManagement`.

[[modules.open, modules.advanced.open]]
=== Open Application Modules

The arrangement described xref:fundamentals.adoc#modules.advanced[above] are considered closed as they only expose types to other modules that are actively selected for exposure.
When applying Spring Modulith to legacy applications, hiding all types located in nested packages from other modules might be inadequate or require marking all those packages for exposure, too.

To turn an application module into an open one, use the `@ApplicationModule` annotation on the `package-info.java` type.

.Declaring an Application Modules as Open
[tabs]
======
Java::
+
[source, java, role="primary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  type = Type.OPEN
)
package example.inventory;
----
Kotlin::
+
[source, kotlin, role="secondary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  type = Type.OPEN
)
package example.inventory
----
======

Declaring an application module as open will cause the following changes to the verification:

* Access to application module internal types from other modules is generally allowed.
* All types, also ones residing in sub-packages of the application module base package are added to the xref:fundamentals.adoc#modules.named-interfaces[unnamed named interface], unless explicitly assigned to a named interface.

NOTE: This feature is intended to be primarily used with code bases of existing projects gradually moving to the Spring Modulith recommended packaging structure.
In a fully-modularized application, using open application modules usually hints at sub-optimal modularization and packaging structures.

[[modules.explicit-dependencies]]
=== Explicit Application Module Dependencies
A module can opt into declaring its allowed dependencies by using the `@ApplicationModule` annotation on the package, represented through the `package-info.java` file.
As, for example, Kotlin lacks support for that file, you can also use the annotation on a single type located in the application module's root package.

.Inventory explicitly configuring module dependencies
[tabs]
======
Java::
+
[source, java, role="primary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  allowedDependencies = "order"
)
package example.inventory;
----
Kotlin::
+
[source, kotlin, role="secondary", chomp="none"]
----
package example.inventory

import org.springframework.modulith.ApplicationModule

@ApplicationModule(allowedDependencies = "order")
class ModuleMetadata {}
----
======

In this case code within the __inventory__ module was only allowed to refer to code in the __order__ module (and code not assigned to any module in the first place).
Find out about how to monitor that in xref:verification.adoc[Verifying Application Module Structure].

[[modules.named-interfaces]]
=== Named Interfaces

By default and as described in xref:fundamentals.adoc#modules.advanced[Advanced Application Modules], an application module's base package is considered the API package and thus is the only package to allow incoming dependencies from other modules.
In case you would like to expose additional packages to other modules, you need to use __named interfaces__.
You achieve that by annotating the `package-info.java` file of those packages with `@NamedInterface` or a type explicitly annotated with `@org.springframework.modulith.PackageInfo`.

.A package arrangement to encapsulate an SPI named interface
[source, text, subs="macros, quotes"]
----
icon:cubes[] Example
└─ icon:folder[] src/main/java
   ├─ icon:cube[] example
   |  └─ icon:plus-circle[role=green] Application.java
   ├─ …
   ├─ icon:cube[] example.order
   |  └─ icon:plus-circle[role=green] OrderManagement.java
   ├─ **icon:cube[] example.order.spi**
   |  ├— icon:coffee[] package-info.java
   |  └─ icon:plus-circle[role=green] SomeSpiInterface.java
   └─ icon:cube[] example.order.internal
      └─ icon:minus-circle[role=red] SomethingOrderInternal.java
----

.`package-info.java` in `example.order.spi`
[tabs]
======
Java::
+
[source, java, role="primary", chomp="none"]
----
@org.springframework.modulith.NamedInterface("spi")
package example.order.spi;
----
Kotlin::
+
[source, kotlin, role="secondary", chomp="none"]
----
package example.order.spi

import org.springframework.modulith.PackageInfo
import org.springframework.modulith.NamedInterface

@PackageInfo
@NamedInterface("spi")
class ModuleMetadata {}
----
======
The effect of that declaration is twofold: first, code in other application modules is allowed to refer to `SomeSpiInterface`.
Application modules are able to refer to the named interface in explicit dependency declarations.
Assume the __inventory__ module was making use of that, it could refer to the above declared named interface like this:

.Defining allowed dependencies to dedicated named interfaces
[tabs]
======
Java::
+
[source, java, role="primary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  allowedDependencies = "order :: spi"
)
package example.inventory;
----
Kotlin::
+
[source, kotlin, role="secondary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  allowedDependencies = "order :: spi"
)
package example.inventory
----
======

Note how we concatenate the named interface's name `spi` via the double colon `::`.
In this setup, code in __inventory__ would be allowed to depend on `SomeSpiInterface` and other code residing in the `order.spi` interface, but not on `OrderManagement` for example.
For modules without explicitly described dependencies, both the application module root package *and* the SPI one are accessible.

If you wanted to express that an application module is allowed to refer to all explicitly declared named interfaces, you can use the asterisk (``*``) as follows:

.Using the asterisk to declare allowed dependencies to all declared named interfaces
[tabs]
======
Java::
+
[source, java, role="primary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  allowedDependencies = "order :: *"
)
package example.inventory;
----
Kotlin::
+
[source, kotlin, role="secondary", chomp="none"]
----
@org.springframework.modulith.ApplicationModule(
  allowedDependencies = "order :: *"
)
package example.inventory
----
======

[[customizing-modules-arrangement]]
== Customizing the Application Modules Arrangement

Spring Moduliths allows to configure some core aspects around the application module arrangement you create via the `@Modulithic` annotation to be used on the main Spring Boot application class.

[tabs]
======
Java::
+
[source, java, role="primary"]
----
package example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.modulith.Modulithic;

@Modulithic
@SpringBootApplication
class MyApplication {

  public static void main(String... args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}
----
Kotlin::
+
[source, kotlin, role="secondary"]
----
package example

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.modulith.Modulithic

@Modulithic
@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
  runApplication<DemoApplication>(*args)
}
----
======

The annotation exposes the following attributes to customize:

[cols="1,3", options="header, unbreakable"]
|===
|Annotation attribute
|Description

|`systemName`
|The human readable name of the application to be used in generated xref:documentation.adoc#documentation[documentation].

|`sharedModules`
|Declares the application modules with the given names as shared modules, which means that they will always be included in xref:testing.adoc#testing[application module integration tests].

|`additionalPackages`
|Instructs Spring Modulith to treat the configured packages as additional root application packages. In other words, application module detection will be triggered for those as well.

|===

[[customizing-modules]]
=== Customizing Module Detection

By default, application modules will be expected to be located in direct sub-packages of the package the Spring Boot application class resides in.
An alternative detection strategy can be activated to only consider package explicitly annotated, either via Spring Modulith's `@ApplicationModule` or jMolecules `@Module` annotation.
That strategy can be activated by configuring the `spring.modulith.detection-strategy` to `explicitly-annotated`.

.Switching the application module detection strategy to only consider annotated packages
[source, text]
----
spring.modulith.detection-strategy=explicitly-annotated
----

If the neither default application module detection strategy nor the manually annotated one does not work for your application, the detection of the modules can be customized by providing an implementation of `ApplicationModuleDetectionStrategy`.
That interface exposes a single method `Stream<JavaPackage> getModuleBasePackages(JavaPackage)` and will be called with the package the Spring Boot application class resides in.
You can then inspect the packages residing within that and select the ones to be considered application module base packages based on a naming convention or the like.

Assume you declare a custom `ApplicationModuleDetectionStrategy` implementation like this:

.Implementing a custom `ApplicationModuleDetectionStrategy`
[tabs]
======
Java::
+
[source, java, role="primary"]
----
package example;

class CustomApplicationModuleDetectionStrategy implements ApplicationModuleDetectionStrategy {

  @Override
  public Stream<JavaPackage> getModuleBasePackages(JavaPackage basePackage) {
    // Your module detection goes here
  }
}
----
Kotlin::
+
[source, kotlin, role="secondary"]
----
package example

class CustomApplicationModuleDetectionStrategy : ApplicationModuleDetectionStrategy {

  override fun getModuleBasePackages(basePackage: JavaPackage): Stream<JavaPackage> {
    // Your module detection goes here
  }
}
----
======

This class can now be registered as `spring.modulith.detection-strategy` as follows:

[source, text]
----
spring.modulith.detection-strategy=example.CustomApplicationModuleDetectionStrategy
----

[[contributing-application-modules]]
=== Contributing Application Modules From Other Packages

While `@Modulithic` allows defining `additionalPackages` to trigger application module detection for packages other than the one of the annotated class, its usage requires knowing about those in advance.
As of version 1.3, Spring Modulith supports external contributions of application modules via the `ApplicationModuleSource` and `ApplicationModuleSourceFactory` abstractions.
An implementation of the latter can be registered in a `spring.factories` file located in `META-INF`.

[source, text]
----
org.springframework.modulith.core.ApplicationModuleSourceFactory=example.CustomApplicationModuleSourceFactory
----

Such a factory can either return arbitrary package names to get an `ApplicationModuleDetectionStrategy` applied, or explicitly return packages to create modules for.

[source, java]
----
package example;

public class CustomApplicationModuleSourceFactory implements ApplicationModuleSourceFactory {

	@Override
	public List<String> getRootPackages() {
		return List.of("com.acme.toscan");
	}

	@Override
	public ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
		return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
	}

	@Override
	public List<String> getModuleBasePackages() {
		return List.of("com.acme.module");
	}
}
----

The above example would use `com.acme.toscan` to detect xref:fundamentals.adoc#customizing-modules[explicitly declared modules] within that and also create an application module from `com.acme.module`.
The package names returned from these will subsequently be translated into ``ApplicationModuleSource``s via the corresponding `getApplicationModuleSource(…)` flavors exposed in `ApplicationModuleDetectionStrategy`.

