├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── 70-splitup
├── initial
│ ├── splitup-initial-inventory
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── resources
│ │ │ │ │ └── application.properties
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── app
│ │ │ │ │ └── InventoryApplication.java
│ │ │ └── test
│ │ │ │ ├── resources
│ │ │ │ └── logback.xml
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── Infrastructure.java
│ │ │ │ └── InitialInventoryTestApplication.java
│ │ └── pom.xml
│ ├── splitup-initial-ecommerce
│ │ ├── src
│ │ │ ├── test
│ │ │ │ ├── resources
│ │ │ │ │ ├── application.properties
│ │ │ │ │ └── logback.xml
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── app
│ │ │ │ │ ├── InitialECommerceTestApplication.java
│ │ │ │ │ ├── Infrastructure.java
│ │ │ │ │ ├── orders
│ │ │ │ │ └── OrdersIntegrationTests.java
│ │ │ │ │ └── inventory
│ │ │ │ │ └── InventoryIntegrationTests.java
│ │ │ └── main
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── orders
│ │ │ │ ├── OrderCompleted.java
│ │ │ │ ├── OrdersController.java
│ │ │ │ └── OrderManagement.java
│ │ │ │ ├── ECommerceApplication.java
│ │ │ │ └── inventory
│ │ │ │ ├── Inventory.java
│ │ │ │ └── InventoryListener.java
│ │ └── pom.xml
│ └── pom.xml
├── complete
│ ├── splitup-complete-ecommerce
│ │ ├── src
│ │ │ ├── test
│ │ │ │ ├── resources
│ │ │ │ │ ├── application.properties
│ │ │ │ │ └── logback.xml
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── app
│ │ │ │ │ ├── CompleteECommerceTestApplication.java
│ │ │ │ │ ├── orders
│ │ │ │ │ └── OrdersIntegrationTests.java
│ │ │ │ │ └── Infrastructure.java
│ │ │ └── main
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── orders
│ │ │ │ ├── OrderCompleted.java
│ │ │ │ ├── OrdersController.java
│ │ │ │ └── OrderManagement.java
│ │ │ │ └── ECommerceApplication.java
│ │ └── pom.xml
│ ├── splitup-complete-inventory
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── app
│ │ │ │ │ │ ├── inventory
│ │ │ │ │ │ ├── OrderCompleted.java
│ │ │ │ │ │ ├── Inventory.java
│ │ │ │ │ │ └── IntegrationListener.java
│ │ │ │ │ │ └── InventoryApplication.java
│ │ │ │ └── resources
│ │ │ │ │ └── application.properties
│ │ │ └── test
│ │ │ │ ├── resources
│ │ │ │ └── logback.xml
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── CompleteInventoryTestApplication.java
│ │ │ │ ├── inventory
│ │ │ │ └── InventoryIntegrationTests.java
│ │ │ │ └── Infrastructure.java
│ │ └── pom.xml
│ └── pom.xml
├── 70-splitup.adoc
└── pom.xml
├── 20-designing-application-modules
├── complete
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── inventory
│ │ │ │ ├── package-info.java
│ │ │ │ └── Inventory.java
│ │ │ │ ├── order
│ │ │ │ ├── persistence
│ │ │ │ │ └── OrderRepository.java
│ │ │ │ └── OrderManagement.java
│ │ │ │ └── Application.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── ApplicationModularityTests.java
│ └── pom.xml
├── 204-lab-explicit-dependencies.adoc
├── 201-article-fundamentals-of-application-module-design.adoc
├── pom.xml
├── 20-designing-application-modules.adoc
├── initial
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── order
│ │ │ │ └── OrderManagement.java
│ │ │ │ └── Application.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── ApplicationModularityTests.java
│ └── pom.xml
└── 203-lab-application-module-relationships.adoc
├── 60-documentation
├── complete
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── package-info.java
│ │ │ │ ├── order
│ │ │ │ ├── package-info.java
│ │ │ │ ├── OrderRepository.java
│ │ │ │ ├── OrderManagement.java
│ │ │ │ └── Order.java
│ │ │ │ ├── customer
│ │ │ │ ├── package-info.java
│ │ │ │ └── Customer.java
│ │ │ │ ├── inventory
│ │ │ │ ├── package-info.java
│ │ │ │ ├── InventoryRepository.java
│ │ │ │ ├── InventorySettings.java
│ │ │ │ └── Inventory.java
│ │ │ │ └── Application.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── ApplicationModularityTests.java
│ └── pom.xml
├── initial
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── package-info.java
│ │ │ │ ├── order
│ │ │ │ ├── package-info.java
│ │ │ │ ├── OrderRepository.java
│ │ │ │ ├── OrderManagement.java
│ │ │ │ └── Order.java
│ │ │ │ ├── customer
│ │ │ │ ├── package-info.java
│ │ │ │ └── Customer.java
│ │ │ │ ├── inventory
│ │ │ │ ├── package-info.java
│ │ │ │ ├── InventoryRepository.java
│ │ │ │ └── Inventory.java
│ │ │ │ └── Application.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── ApplicationModularityTests.java
│ └── pom.xml
├── pom.xml
└── 60-documentation.adoc
├── src
└── docs
│ └── asciidoc
│ ├── images
│ ├── domain.png
│ └── splitup.jpeg
│ └── index.adoc
├── readme.adoc
├── 30-event-based-integration
├── complete
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── order
│ │ │ │ ├── OrderCompleted.java
│ │ │ │ ├── OrderRepository.java
│ │ │ │ ├── Order.java
│ │ │ │ ├── EmailSender.java
│ │ │ │ └── OrderManagement.java
│ │ │ │ ├── Application.java
│ │ │ │ └── inventory
│ │ │ │ └── Inventory.java
│ │ └── test
│ │ │ ├── resources
│ │ │ └── logback.xml
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── ApplicationModularityTests.java
│ │ │ └── order
│ │ │ └── OrderManagementIntegrationTests.java
│ └── pom.xml
├── initial
│ ├── src
│ │ ├── test
│ │ │ ├── resources
│ │ │ │ └── logback.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ └── order
│ │ │ │ └── OrderManagementIntegrationTests.java
│ │ └── main
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── order
│ │ │ ├── OrderRepository.java
│ │ │ ├── Order.java
│ │ │ ├── EmailSender.java
│ │ │ └── OrderManagement.java
│ │ │ ├── Application.java
│ │ │ └── inventory
│ │ │ └── Inventory.java
│ └── pom.xml
└── pom.xml
├── .gitignore
├── 40-integration-testing
├── 40-integration-testing.adoc
├── complete
│ └── pom.xml
├── initial
│ └── pom.xml
└── pom.xml
├── 10-fundamentals
├── 10-fundamentals.adoc
├── pom.xml
├── complete
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── order
│ │ │ │ └── OrderManagement.java
│ │ │ │ └── Application.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── ApplicationModularityTests.java
│ └── pom.xml
├── initial
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── app
│ │ └── Application.java
├── 101-setup.adoc
└── 102-creating-modules.adoc
├── .educates
├── files
│ └── workshop
│ │ ├── profile
│ │ └── setup.d
│ │ └── set-up-env.sh
└── prep4educates.sh
├── .github
└── workflows
│ └── build-all.yaml
├── 50-jmolecules
├── pom.xml
├── initial
│ └── pom.xml
├── complete
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── app
│ │ │ │ ├── Application.java
│ │ │ │ ├── catalog
│ │ │ │ ├── ProductRepository.java
│ │ │ │ └── Product.java
│ │ │ │ ├── inventory
│ │ │ │ ├── InventoryItemRepository.java
│ │ │ │ └── InventoryItem.java
│ │ │ │ └── orders
│ │ │ │ ├── OrderRepository.java
│ │ │ │ ├── LineItem.java
│ │ │ │ └── Order.java
│ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── catalog
│ │ │ ├── ArchitectureTests.java
│ │ │ └── ProductRepositoryIntegrationTests.java
│ │ │ └── orders
│ │ │ └── OrderRepositoryIntegrationTests.java
│ └── pom.xml
└── 50-jmolecules.adoc
├── 00-introduction
├── 000-article-the-domain.adoc
└── 00-introduction.adoc
├── pom.xml
└── mvnw.cmd
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/odrotbohm/spring-modulith-deep-dive/HEAD/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.kafka.consumer.group-id=inventory
2 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/main/java/com/example/app/inventory/package-info.java:
--------------------------------------------------------------------------------
1 | package com.example.app.inventory;
2 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app;
3 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app;
3 |
--------------------------------------------------------------------------------
/src/docs/asciidoc/images/domain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/odrotbohm/spring-modulith-deep-dive/HEAD/src/docs/asciidoc/images/domain.png
--------------------------------------------------------------------------------
/src/docs/asciidoc/images/splitup.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/odrotbohm/spring-modulith-deep-dive/HEAD/src/docs/asciidoc/images/splitup.jpeg
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.modulith.events.jdbc.schema-initialization.enabled=true
2 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/order/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.order;
3 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/order/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.order;
3 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/customer/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.customer;
3 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/inventory/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.inventory;
3 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/customer/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.customer;
3 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/inventory/package-info.java:
--------------------------------------------------------------------------------
1 | @org.springframework.lang.NonNullApi
2 | package com.example.app.inventory;
3 |
--------------------------------------------------------------------------------
/20-designing-application-modules/204-lab-explicit-dependencies.adoc:
--------------------------------------------------------------------------------
1 | [[module-design.explicit-dependencies]]
2 | = 👣 Explicit Application Module Dependencies
3 |
4 |
5 |
--------------------------------------------------------------------------------
/readme.adoc:
--------------------------------------------------------------------------------
1 | = Spring Modulith Deep Dive Workshop
2 |
3 | == Preparations
4 | [source, bash]
5 | -----
6 | $ ./mvnw -Pdocs -N
7 | $ open target/generated-docs/index.html
8 | -----
9 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.modulith.events.jdbc.schema-initialization.enabled=true
2 | spring.modulith.kafka.enable-json=false
3 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/order/OrderCompleted.java:
--------------------------------------------------------------------------------
1 | package com.example.app.order;
2 |
3 | import java.util.UUID;
4 |
5 | public record OrderCompleted(UUID orderIdentifier) {}
6 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/main/java/com/example/app/inventory/OrderCompleted.java:
--------------------------------------------------------------------------------
1 | package com.example.app.inventory;
2 |
3 | import java.util.UUID;
4 |
5 | public record OrderCompleted(UUID id) {}
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | .idea/
3 | .flattened-pom.xml
4 | .settings/
5 | *.iml
6 | .project
7 | .classpath
8 | .springBeans
9 | target/
10 | .factorypath
11 | changelog.txt
12 |
13 | #IntelliJ Stuff
14 | .idea
15 | *.iml
16 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.kafka.consumer.group-id=inventory
2 | spring.modulith.events.kafka.enable-json=false
3 | spring.modulith.events.jdbc.schema-initialization.enabled=true
4 |
--------------------------------------------------------------------------------
/20-designing-application-modules/201-article-fundamentals-of-application-module-design.adoc:
--------------------------------------------------------------------------------
1 | [[module-design.module-api-defaults]]
2 | = 📖 Fundamentals of Application Module design
3 |
4 | - Application module's base package considered its API package.
5 | - Any nested package is considered module-internal. Code residing in it is not allowed to be accessed by other application modules.
6 |
7 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/orders/OrderCompleted.java:
--------------------------------------------------------------------------------
1 | package com.example.app.orders;
2 |
3 | import java.util.UUID;
4 |
5 | import org.jmolecules.event.annotation.Externalized;
6 | import org.jmolecules.event.types.DomainEvent;
7 |
8 | @Externalized("orders.OrderCompleted")
9 | public record OrderCompleted(UUID id) implements DomainEvent {}
10 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/main/java/com/example/app/orders/OrderCompleted.java:
--------------------------------------------------------------------------------
1 | package com.example.app.orders;
2 |
3 | import java.util.UUID;
4 |
5 | import org.jmolecules.event.annotation.Externalized;
6 | import org.jmolecules.event.types.DomainEvent;
7 |
8 | @Externalized("orders.OrderCompleted")
9 | public record OrderCompleted(UUID id) implements DomainEvent {}
10 |
--------------------------------------------------------------------------------
/70-splitup/70-splitup.adoc:
--------------------------------------------------------------------------------
1 | [[splitup]]
2 | = Splitting the Modulith
3 | :imagesdir: ../src/docs/asciidoc/images
4 |
5 | ifdef::educates[]
6 | [source, terminal:execute-all]
7 | ----
8 | command: cd ~/exercises && clear
9 | autostart: true
10 | hidden: true
11 | ----
12 |
13 | [source, dashboard:reload-dashboard]
14 | ----
15 | name: Editor
16 | autostart: true
17 | hidden: true
18 | ----
19 | endif::[]
20 |
21 | [[splitup.introduction]]
22 | == 📖 Introduction
23 |
24 | image::splitup.jpeg[]
25 |
26 |
--------------------------------------------------------------------------------
/40-integration-testing/40-integration-testing.adoc:
--------------------------------------------------------------------------------
1 | = Integration testing modules
2 |
3 | ifdef::educates[]
4 | [source, terminal:execute-all]
5 | ----
6 | command: cd ~/exercises && clear
7 | autostart: true
8 | hidden: true
9 | ----
10 |
11 | [source, dashboard:reload-dashboard]
12 | ----
13 | name: Editor
14 | autostart: true
15 | hidden: true
16 | ----
17 | endif::[]
18 |
19 | == 🧑💻 -- Running Application Module-Specific Integration Tests
20 |
21 | == 🧑💻 -- Testing more complex flows using `Scenarios`
22 |
--------------------------------------------------------------------------------
/10-fundamentals/10-fundamentals.adoc:
--------------------------------------------------------------------------------
1 | [[fundamentals]]
2 | = Fundamentals
3 | :tabsize: 2
4 |
5 | ifndef::educates[]
6 |
7 | include::101-setup.adoc[leveloffset=+1]
8 | include::102-creating-modules.adoc[leveloffset=+1]
9 |
10 | endif::[]
11 |
12 | ifdef::educates[]
13 | [source, terminal:execute-all]
14 | ----
15 | command: cd ~/exercises && clear
16 | autostart: true
17 | hidden: true
18 | ----
19 |
20 | [source, dashboard:reload-dashboard]
21 | ----
22 | name: Editor
23 | autostart: true
24 | hidden: true
25 | ----
26 | endif::[]
27 |
--------------------------------------------------------------------------------
/.educates/files/workshop/profile:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script is run after ~/.bash_profile
4 | # For more information, see:
5 | # https://docs.educates.dev/workshop-content/workshop-runtime.html#terminal-user-shell-environment
6 |
7 | # Customize the prompt to make it easier on the eyes
8 | export PS1_OLD="$PS1"
9 | #export PS1="\n\[\033[33m\]\w\$ \[\033[0m\]"%
10 | export PS1="\n\[\033[33m\][\w] $ \[\033[0m\]"
11 | #export PS1='\n`echo -n \[\e[1\;33m\]`[\w] $ `echo \[\e[0m\]`'
12 |
13 | # Enable finding ~/exercises/mvnw on PATH
14 | export PATH=~/code:$PATH
--------------------------------------------------------------------------------
/.github/workflows/build-all.yaml:
--------------------------------------------------------------------------------
1 | name: Maven Build
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | name: Build project
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 |
16 | - name: Check out sources
17 | uses: actions/checkout@v4
18 | with:
19 | fetch-depth: 0
20 |
21 | - name: Set up JDK 21
22 | uses: actions/setup-java@v4
23 | with:
24 | distribution: 'temurin'
25 | java-version: 21
26 | cache: 'maven'
27 |
28 | - name: Build with Maven
29 | run: ./mvnw -B clean verify
30 |
--------------------------------------------------------------------------------
/40-integration-testing/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | integration-testing-complete
7 |
8 |
9 | de.odrotbohm.smdd
10 | integration-testing
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 4 - Integration Testing - Complete
16 |
17 |
18 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | package com.example.app;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
6 | import org.springframework.scheduling.annotation.EnableAsync;
7 |
8 | /**
9 | * Spring for the architecturally curious developer
10 | *
11 | * @author Oliver Drotbohm (@odrotbohm)
12 | */
13 | @EnableAsync
14 | @SpringBootApplication
15 | @ConfigurationPropertiesScan
16 | public class Application {
17 |
18 | public static void main(String[] args) {
19 | SpringApplication.run(Application.class, args);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | package com.example.app;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
6 | import org.springframework.scheduling.annotation.EnableAsync;
7 |
8 | /**
9 | * Spring for the architecturally curious developer
10 | *
11 | * @author Oliver Drotbohm (@odrotbohm)
12 | */
13 | @EnableAsync
14 | @SpringBootApplication
15 | @ConfigurationPropertiesScan
16 | public class Application {
17 |
18 | public static void main(String[] args) {
19 | SpringApplication.run(Application.class, args);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/40-integration-testing/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.odrotbohm.smdd
7 | integration-testing-initial
8 | 1.0-SNAPSHOT
9 |
10 |
11 | de.odrotbohm.smdd
12 | integration-testing
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 | 4 - Integration Testing - Initial
18 |
19 |
20 |
--------------------------------------------------------------------------------
/70-splitup/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup
7 |
8 | 7 - Splitup
9 |
10 |
11 | de.odrotbohm.smdd
12 | spring-modulith-deep-dive
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 | pom
18 |
19 |
20 | complete
21 | initial
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/50-jmolecules/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | jmolecules
7 | pom
8 |
9 |
10 | de.odrotbohm.smdd
11 | spring-modulith-deep-dive
12 | 1.0-SNAPSHOT
13 | ../pom.xml
14 |
15 |
16 | 5 - jMolecules
17 |
18 |
19 | complete
20 | initial
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/10-fundamentals/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | fundamentals
7 | pom
8 |
9 |
10 | de.odrotbohm.smdd
11 | spring-modulith-deep-dive
12 | 1.0-SNAPSHOT
13 | ../pom.xml
14 |
15 |
16 | 1 - Fundamentals
17 |
18 |
19 | complete
20 | initial
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/60-documentation/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | documentation
7 | pom
8 |
9 |
10 | de.odrotbohm.smdd
11 | spring-modulith-deep-dive
12 | 1.0-SNAPSHOT
13 | ../pom.xml
14 |
15 |
16 | 6 - Documentation
17 |
18 |
19 | complete
20 | initial
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/docs/asciidoc/index.adoc:
--------------------------------------------------------------------------------
1 | = Spring Modulith Deep-Dive
2 | :toc: left
3 | :index-link:
4 | :iconfont-fontawesome:
5 | :sectnums:
6 | :sectnumlevels: 2
7 |
8 | include::../../../00-introduction/00-introduction.adoc[leveloffset=+1]
9 | include::../../../10-fundamentals/10-fundamentals.adoc[leveloffset=+1]
10 | include::../../../20-designing-application-modules/20-designing-application-modules.adoc[leveloffset=+1]
11 | include::../../../30-event-based-integration/30-event-based-integration.adoc[leveloffset=+1]
12 | include::../../../40-integration-testing/40-integration-testing.adoc[leveloffset=+1]
13 | include::../../../50-jmolecules/50-jmolecules.adoc[leveloffset=+1]
14 | include::../../../60-documentation/60-documentation.adoc[leveloffset=+1]
15 | include::../../../70-splitup/70-splitup.adoc[leveloffset=+1]
16 |
17 |
--------------------------------------------------------------------------------
/40-integration-testing/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.odrotbohm.smdd
7 | integration-testing
8 | pom
9 |
10 |
11 | de.odrotbohm.smdd
12 | spring-modulith-deep-dive
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 | 4 - Integration Testing
18 |
19 |
20 | complete
21 | initial
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/30-event-based-integration/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.odrotbohm.smdd
7 | event-based-integration
8 | pom
9 |
10 |
11 | de.odrotbohm.smdd
12 | spring-modulith-deep-dive
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 | 3 - Event-Based Integration
18 |
19 |
20 | complete
21 | initial
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/20-designing-application-modules/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.odrotbohm.smdd
7 | designing-application-modules
8 | pom
9 |
10 |
11 | de.odrotbohm.smdd
12 | spring-modulith-deep-dive
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 | 2 - Designing Application Modules
18 |
19 |
20 | complete
21 | initial
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/20-designing-application-modules/20-designing-application-modules.adoc:
--------------------------------------------------------------------------------
1 | [[module-design]]
2 | = Designing Application Modules
3 | :tabsize: 2
4 | :source: complete/src/main/java/com/example/app
5 | :test-source: complete/src/test/java/com/example/app
6 |
7 | ifndef::educates[]
8 | include::201-article-fundamentals-of-application-module-design.adoc[leveloffset=+1]
9 | include::202-lab-application-module-visibility.adoc[leveloffset=+1]
10 | include::203-lab-application-module-relationships.adoc[leveloffset=+1]
11 | include::204-lab-explicit-dependencies.adoc[leveloffset=+1]
12 | endif::[]
13 |
14 | ifdef::educates[]
15 | [source, terminal:execute-all]
16 | ----
17 | command: cd ~/exercises && clear
18 | autostart: true
19 | hidden: true
20 | ----
21 |
22 | [source, dashboard:reload-dashboard]
23 | ----
24 | name: Editor
25 | autostart: true
26 | hidden: true
27 | ----
28 | endif::[]
29 |
--------------------------------------------------------------------------------
/20-designing-application-modules/initial/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import org.springframework.stereotype.Component;
19 |
20 | @Component
21 | public class OrderManagement {}
22 |
--------------------------------------------------------------------------------
/10-fundamentals/complete/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | // tag::class[]
17 | package com.example.app.order;
18 |
19 | import org.springframework.stereotype.Component;
20 |
21 | @Component
22 | public class OrderManagement {}
23 | // end::class[]
24 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/inventory/InventoryRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import org.jmolecules.ddd.annotation.Repository;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | @Repository
24 | class InventoryRepository {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/inventory/InventoryRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import org.jmolecules.ddd.annotation.Repository;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | @Repository
24 | class InventoryRepository {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/src/test/java/com/example/app/Infrastructure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.test.context.TestConfiguration;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | @TestConfiguration
24 | public class Infrastructure {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/10-fundamentals/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | fundamentals-initial
7 |
8 |
9 | de.odrotbohm.smdd
10 | fundamentals
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 1 - Fundamentals - Initial
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/main/java/com/example/app/order/persistence/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order.persistence;
17 |
18 | import org.springframework.stereotype.Repository;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | @Repository
24 | public class OrderRepository {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/50-jmolecules/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | jmolecules-initial
7 |
8 | 5 - jMolecules - Initial
9 |
10 |
11 | de.odrotbohm.smdd
12 | jmolecules
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter-data-jpa
22 |
23 |
24 |
25 | com.h2database
26 | h2
27 | runtime
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/order/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import java.util.UUID;
19 |
20 | import org.springframework.data.repository.CrudRepository;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | interface OrderRepository extends CrudRepository {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/order/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import java.util.UUID;
19 |
20 | import org.springframework.data.repository.CrudRepository;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | interface OrderRepository extends CrudRepository {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/order/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import org.springframework.data.repository.CrudRepository;
19 |
20 | import com.example.app.order.Order.OrderIdentifier;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | interface OrderRepository extends CrudRepository {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/order/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import org.springframework.data.repository.CrudRepository;
19 |
20 | import com.example.app.order.Order.OrderIdentifier;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | interface OrderRepository extends CrudRepository {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.modulith.core.ApplicationModules;
20 |
21 | class ApplicationModularityTests {
22 |
23 | @Test
24 | void writeDocumentation() {
25 |
26 | var modules = ApplicationModules.of(Application.class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.stereotype.Component;
21 |
22 | import com.example.app.order.persistence.OrderRepository;
23 |
24 | @Component
25 | @RequiredArgsConstructor
26 | public class Inventory {
27 |
28 | private final OrderRepository repository;
29 | }
30 |
--------------------------------------------------------------------------------
/10-fundamentals/complete/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/10-fundamentals/initial/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | // tag::class[]
18 | package com.example.app.order;
19 |
20 | import lombok.RequiredArgsConstructor;
21 |
22 | import org.springframework.stereotype.Component;
23 |
24 | import com.example.app.order.persistence.OrderRepository;
25 |
26 | @Component
27 | @RequiredArgsConstructor
28 | public class OrderManagement {
29 |
30 | private final OrderRepository repository;
31 | }
32 | // end::class[]
33 |
--------------------------------------------------------------------------------
/20-designing-application-modules/initial/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/catalog/ProductRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.catalog;
17 |
18 | import java.util.Optional;
19 |
20 | import org.springframework.data.repository.CrudRepository;
21 |
22 | import com.example.app.catalog.Product.ProductIdentifier;
23 |
24 | /**
25 | * @author Oliver Drotbohm
26 | */
27 | public interface ProductRepository extends CrudRepository {
28 |
29 | Optional findByName(String name);
30 | }
31 |
--------------------------------------------------------------------------------
/10-fundamentals/complete/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.modulith.core.ApplicationModules;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | class ApplicationModularityTests {
25 |
26 | @Test
27 | void bootstrapsApplicationModules() {
28 |
29 | var modules = ApplicationModules.of(Application.class);
30 |
31 | System.out.println(modules);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class Application {
26 |
27 | public static void main(String... args) throws Exception {
28 | SpringApplication.run(Application.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/test/java/com/example/app/CompleteInventoryTestApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | class CompleteInventoryTestApplication {
24 |
25 | public static void main(String[] args) throws Exception {
26 |
27 | SpringApplication.from(InventoryApplication::main)
28 | .with(Infrastructure.class)
29 | .run(args);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/java/com/example/app/InitialECommerceTestApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | public class InitialECommerceTestApplication {
24 |
25 | public static void main(String[] args) throws Exception {
26 |
27 | SpringApplication.from(ECommerceApplication::main)
28 | .with(Infrastructure.class)
29 | .run(args);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.modulith.core.ApplicationModules;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | class ApplicationModularityTests {
25 |
26 | @Test
27 | void bootstrapsApplicationModules() {
28 |
29 | var modules = ApplicationModules.of(Application.class);
30 |
31 | System.out.println(modules);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/test/java/com/example/app/CompleteECommerceTestApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 |
20 | /**
21 | * @author Oliver Drotbohm
22 | */
23 | public class CompleteECommerceTestApplication {
24 |
25 | public static void main(String[] args) throws Exception {
26 |
27 | SpringApplication.from(ECommerceApplication::main)
28 | .with(Infrastructure.class)
29 | .run(args);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/20-designing-application-modules/initial/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.modulith.core.ApplicationModules;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | class ApplicationModularityTests {
25 |
26 | @Test
27 | void bootstrapsApplicationModules() {
28 |
29 | var modules = ApplicationModules.of(Application.class);
30 |
31 | System.out.println(modules);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/ECommerceApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class ECommerceApplication {
26 |
27 | public static void main(String[] args) throws Exception {
28 | SpringApplication.run(ECommerceApplication.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/src/main/java/com/example/app/InventoryApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class InventoryApplication {
26 |
27 | public static void main(String[] args) throws Exception {
28 | SpringApplication.run(InventoryApplication.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/main/java/com/example/app/ECommerceApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class ECommerceApplication {
26 |
27 | public static void main(String[] args) throws Exception {
28 | SpringApplication.run(ECommerceApplication.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/main/java/com/example/app/InventoryApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @SpringBootApplication
25 | public class InventoryApplication {
26 |
27 | public static void main(String[] args) throws Exception {
28 | SpringApplication.run(InventoryApplication.class, args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.autoconfigure.SpringBootApplication;
20 | import org.springframework.scheduling.annotation.EnableAsync;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | @EnableAsync
26 | @SpringBootApplication
27 | public class Application {
28 |
29 | public static void main(String... args) throws Exception {
30 | SpringApplication.run(Application.class, args);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | // tag::modularityTests[]
17 | package com.example.app;
18 |
19 | import org.junit.jupiter.api.Test;
20 | import org.springframework.modulith.core.ApplicationModules;
21 | import org.springframework.modulith.docs.Documenter;
22 |
23 | class ApplicationModularityTests {
24 |
25 | @Test
26 | void writeDocumentation() {
27 |
28 | var modules = ApplicationModules.of(Application.class);
29 |
30 | new Documenter(modules).writeDocumentation();
31 | }
32 | }
33 | // end::modularityTests[]
34 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/test/java/com/example/app/catalog/ArchitectureTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.catalog;
17 |
18 | import org.jmolecules.archunit.JMoleculesDddRules;
19 |
20 | import com.example.app.Application;
21 | import com.tngtech.archunit.junit.AnalyzeClasses;
22 | import com.tngtech.archunit.junit.ArchTest;
23 | import com.tngtech.archunit.lang.ArchRule;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @AnalyzeClasses(packagesOf = Application.class)
29 | class ArchitectureTests {
30 |
31 | @ArchTest ArchRule ddd = JMoleculesDddRules.all();
32 | }
33 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/src/test/java/com/example/app/InitialInventoryTestApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.SpringApplication;
19 | import org.springframework.boot.test.context.TestConfiguration;
20 |
21 | /**
22 | * @author Oliver Drotbohm
23 | */
24 | @TestConfiguration
25 | class InitialInventoryTestApplication {
26 |
27 | public static void main(String[] args) throws Exception {
28 |
29 | SpringApplication.from(InventoryApplication::main)
30 | .with(Infrastructure.class)
31 | .run(args);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.extern.slf4j.Slf4j;
19 |
20 | import org.springframework.stereotype.Service;
21 | import org.springframework.transaction.annotation.Transactional;
22 |
23 | import com.example.app.order.Order;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @Slf4j
29 | @Service
30 | @Transactional
31 | public class Inventory {
32 |
33 | public void updateStockFor(Order order) {
34 | log.info("Updating stock for {}", order.getId());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/order/Order.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.persistence.Entity;
19 | import jakarta.persistence.Id;
20 | import jakarta.persistence.Table;
21 | import lombok.Getter;
22 |
23 | import java.util.UUID;
24 |
25 | @Entity
26 | @Getter
27 | @Table(name = "MyOrder")
28 | public class Order {
29 |
30 | private final @Id UUID id;
31 | private boolean completed;
32 |
33 | Order() {
34 | this.id = UUID.randomUUID();
35 | }
36 |
37 | Order complete() {
38 | this.completed = true;
39 | return this;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/order/Order.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.persistence.Entity;
19 | import jakarta.persistence.Id;
20 | import jakarta.persistence.Table;
21 | import lombok.Getter;
22 |
23 | import java.util.UUID;
24 |
25 | @Entity
26 | @Getter
27 | @Table(name = "MyOrder")
28 | public class Order {
29 |
30 | private final @Id UUID id;
31 | private boolean completed;
32 |
33 | Order() {
34 | this.id = UUID.randomUUID();
35 | }
36 |
37 | Order complete() {
38 | this.completed = true;
39 | return this;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/main/java/com/example/app/orders/OrdersController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.web.bind.annotation.PostMapping;
21 | import org.springframework.web.bind.annotation.RestController;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | @RestController
27 | @RequiredArgsConstructor
28 | class OrdersController {
29 |
30 | private final OrderManagement orders;
31 |
32 | @PostMapping("/orders/complete")
33 | void complete() {
34 | orders.complete();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/orders/OrdersController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.web.bind.annotation.PostMapping;
21 | import org.springframework.web.bind.annotation.RestController;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | @RestController
27 | @RequiredArgsConstructor
28 | class OrdersController {
29 |
30 | private final OrderManagement orders;
31 |
32 | @PostMapping("/orders/complete")
33 | void complete() {
34 | orders.complete();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/test/java/com/example/app/order/OrderManagementIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.boot.test.context.SpringBootTest;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | @SpringBootTest
26 | // @Transactional
27 | class OrderManagementIntegrationTests {
28 |
29 | @Autowired OrderManagement orders;
30 |
31 | @Test
32 | void completesOrder() throws InterruptedException {
33 | orders.complete(new Order());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.context.ApplicationEventPublisher;
21 | import org.springframework.stereotype.Component;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | @Component
27 | @RequiredArgsConstructor
28 | public class Inventory {
29 |
30 | private final ApplicationEventPublisher events;
31 |
32 | public void update() {
33 | events.publishEvent(new InventoryUpdated());
34 | }
35 |
36 | record InventoryUpdated() {}
37 | }
38 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.context.ApplicationEventPublisher;
21 | import org.springframework.stereotype.Component;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | @Component
27 | @RequiredArgsConstructor
28 | public class Inventory {
29 |
30 | private final ApplicationEventPublisher events;
31 |
32 | public void update() {
33 | events.publishEvent(new InventoryUpdated());
34 | }
35 |
36 | record InventoryUpdated() {}
37 | }
38 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/src/test/java/com/example/app/ApplicationModularityTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.springframework.modulith.core.ApplicationModules;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | class ApplicationModularityTests {
27 |
28 | @Test
29 | void bootstrapsApplicationModules() {
30 |
31 | var modules = ApplicationModules.of(Application.class);
32 |
33 | System.out.println(modules);
34 |
35 | assertThatException()
36 | .isThrownBy(() -> modules.verify());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/test/java/com/example/app/order/OrderManagementIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.boot.test.context.SpringBootTest;
21 |
22 | /**
23 | * @author Oliver Drotbohm
24 | */
25 | @SpringBootTest
26 | class OrderManagementIntegrationTests {
27 |
28 | @Autowired OrderManagement orders;
29 |
30 | @Test
31 | void reducesStockOnOrderCompletion() throws InterruptedException {
32 |
33 | orders.complete(new Order());
34 |
35 | Thread.sleep(2000);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/inventory/InventoryListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.springframework.modulith.events.ApplicationModuleListener;
21 | import org.springframework.stereotype.Component;
22 |
23 | import com.example.app.orders.OrderCompleted;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @Component
29 | @RequiredArgsConstructor
30 | class InventoryListener {
31 |
32 | private final Inventory inventory;
33 |
34 | @ApplicationModuleListener
35 | void on(OrderCompleted event) {
36 | inventory.update();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/inventory/InventorySettings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.AccessLevel;
19 | import lombok.RequiredArgsConstructor;
20 | import lombok.Value;
21 |
22 | import org.springframework.boot.context.properties.ConfigurationProperties;
23 | import org.springframework.boot.context.properties.bind.ConstructorBinding;
24 |
25 | @Value
26 | @RequiredArgsConstructor(access = AccessLevel.PACKAGE, onConstructor = @__(@ConstructorBinding))
27 | @ConfigurationProperties("example.inventory")
28 | class InventorySettings {
29 |
30 | /**
31 | * Some Javadoc.
32 | */
33 | int stockThreshold;
34 | }
35 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/java/com/example/app/Infrastructure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.test.context.TestConfiguration;
19 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
20 | import org.springframework.context.annotation.Bean;
21 | import org.testcontainers.containers.PostgreSQLContainer;
22 |
23 | /**
24 | * @author Oliver Drotbohm
25 | */
26 | @TestConfiguration
27 | public class Infrastructure {
28 |
29 | @Bean
30 | @ServiceConnection
31 | PostgreSQLContainer> postgresContainer() {
32 | return new PostgreSQLContainer<>("postgres:latest");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/main/java/com/example/app/inventory/IntegrationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 | import lombok.extern.slf4j.Slf4j;
20 |
21 | import org.springframework.kafka.annotation.KafkaListener;
22 | import org.springframework.stereotype.Component;
23 |
24 | @Slf4j
25 | @Component
26 | @RequiredArgsConstructor
27 | class IntegrationListener {
28 |
29 | private final Inventory inventory;
30 |
31 | @KafkaListener(topics = "orders.OrderCompleted")
32 | void on(OrderCompleted event) {
33 |
34 | log.info("Received event: {}", event);
35 |
36 | inventory.update();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/50-jmolecules/50-jmolecules.adoc:
--------------------------------------------------------------------------------
1 | [[arch-evident-code]]
2 | = Architecturally-Evident Code Using jMolecules
3 |
4 | ifdef::educates[]
5 | [source, terminal:execute-all]
6 | ----
7 | command: cd ~/exercises && clear
8 | autostart: true
9 | hidden: true
10 | ----
11 |
12 | [source, dashboard:reload-dashboard]
13 | ----
14 | name: Editor
15 | autostart: true
16 | hidden: true
17 | ----
18 | endif::[]
19 |
20 | [[arch-evident-code.fundamentals]]
21 | == 📖 -- jMolecules Fundamentals
22 |
23 | [[arch-evident-code.project-setup]]
24 | == 🧑💻 -- Add jMolecules to the project
25 |
26 | ifndef::educates[]
27 | [TIP]
28 | endif::[]
29 |
30 | ifdef::educates[]
31 | [quote]
32 | ____
33 | **Tip** +
34 | endif::[]
35 | Use the Spring CLI's `jmolecules init` command to add the basic setup of jMolecules to your project.
36 | ifdef::educates[]
37 | ____
38 | endif::[]
39 |
40 | [[arch-evident-code.boilerplate]]
41 | == 📖 -- Avoiding Boilerplate Code with jMolecules Integrations
42 |
43 | [[arch-evident-code.jpa-aggregates]]
44 | == 🧑💻 -- Persisting Aggregates with JPA
45 |
46 | ifndef::educates[]
47 | [TIP]
48 | endif::[]
49 | ifdef::educates[]
50 | [quote]
51 | ____
52 | **Tip** +
53 | endif::[]
54 | Use the Spring CLI's `jmolecules add-aggregate` command to add an aggregate and supporting abstractions to the project.
55 | ifdef::educates[]
56 | ____
57 | endif::[]
58 |
59 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/order/EmailSender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import lombok.extern.slf4j.Slf4j;
19 |
20 | import java.util.UUID;
21 |
22 | import org.springframework.stereotype.Component;
23 |
24 | /**
25 | * @author Oliver Drotbohm
26 | */
27 | @Slf4j
28 | @Component
29 | class EmailSender {
30 |
31 | void sendEmailFor(UUID orderIdentifier) {
32 |
33 | log.info("Sending email for order {}.", orderIdentifier);
34 |
35 | try {
36 | Thread.sleep(1000);
37 | } catch (InterruptedException o_O) {}
38 |
39 | // throw new RuntimeException();
40 |
41 | log.info("Email sent for order {}.", orderIdentifier);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/main/java/com/example/app/orders/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import java.util.UUID;
21 |
22 | import org.springframework.context.ApplicationEventPublisher;
23 | import org.springframework.stereotype.Component;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | /**
27 | * @author Oliver Drotbohm
28 | */
29 | @Transactional
30 | @Component
31 | @RequiredArgsConstructor
32 | public class OrderManagement {
33 |
34 | private final ApplicationEventPublisher events;
35 |
36 | public void complete() {
37 | events.publishEvent(new OrderCompleted(UUID.randomUUID()));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/main/java/com/example/app/orders/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import java.util.UUID;
21 |
22 | import org.springframework.context.ApplicationEventPublisher;
23 | import org.springframework.stereotype.Component;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | /**
27 | * @author Oliver Drotbohm
28 | */
29 | @Transactional
30 | @Component
31 | @RequiredArgsConstructor
32 | public class OrderManagement {
33 |
34 | private final ApplicationEventPublisher events;
35 |
36 | public void complete() {
37 | events.publishEvent(new OrderCompleted(UUID.randomUUID()));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/10-fundamentals/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | fundamentals-complete
7 |
8 |
9 | de.odrotbohm.smdd
10 | fundamentals
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 1 - Fundamentals - Complete
16 |
17 |
18 |
19 |
20 | org.springframework.modulith
21 | spring-modulith-bom
22 | ${spring-modulith.version}
23 | pom
24 | import
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 |
39 |
40 | org.springframework.modulith
41 | spring-modulith-starter-test
42 | test
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/.educates/files/workshop/setup.d/set-up-env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Trim the value of the environment variable if it exists
4 | exercisesDir="${EXERCISES_DIR// /}" # Removes spaces from the beginning and end
5 |
6 | vscodeFile=~/.vscode/settings.json
7 | mkdir -p ~/.vscode
8 |
9 | # Check if the environment variable exists and is not empty or blank
10 | # Also, check if the trimmed value represents an existing directory on disk
11 | if [ -n "$exercisesDir" ] && eval [ -d $exercisesDir ]; then
12 |
13 | # Create a symbolic link from ~exercises to the current lab code
14 | echo "Linking ~/exercises to $exercisesDir"
15 | if [ ! -L ~/exercises ]; then
16 | eval ln -s $exercisesDir ~/exercises
17 | fi
18 |
19 | # Configure VSCode
20 | echo "Creating '$vscodeFile' to control visible files in VSCode (show only ~/exercises/*)"
21 | cat << EOF > "$vscodeFile"
22 | {
23 | "files.exclude": {
24 | "**/.*": true,
25 | "**/code": true,
26 | "**/exercises/**": false,
27 | }
28 | }
29 | EOF
30 |
31 | else
32 | echo "[WARNING] The environment variable EXERCISES_DIR does not exist, is empty or blank, or does not represent an existing directory on disk"
33 |
34 | # Configure VSCode
35 | echo "Creating '$vscodeFile' to control visible files in VSCode (hide all 'dot' files)"
36 | cat << EOF > "$vscodeFile"
37 | {
38 | "files.exclude": {
39 | "**/.*": true,
40 | }
41 | }
42 | EOF
43 |
44 | fi
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/customer/Customer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.customer;
17 |
18 | import lombok.Getter;
19 |
20 | import java.util.UUID;
21 |
22 | import org.jmolecules.ddd.types.AggregateRoot;
23 | import org.jmolecules.ddd.types.Identifier;
24 |
25 | import com.example.app.customer.Customer.CustomerIdentifier;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | @Getter
31 | public class Customer implements AggregateRoot {
32 |
33 | private final CustomerIdentifier id;
34 | private final String address;
35 |
36 | public Customer(String address) {
37 |
38 | this.id = new CustomerIdentifier(UUID.randomUUID());
39 | this.address = address;
40 | }
41 |
42 | public record CustomerIdentifier(UUID id) implements Identifier {}
43 | }
44 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.transaction.Transactional;
19 | import lombok.RequiredArgsConstructor;
20 |
21 | import org.jmolecules.ddd.annotation.Service;
22 |
23 | import com.example.app.customer.Customer.CustomerIdentifier;
24 |
25 | /**
26 | * The primary application service of the order module.
27 | *
28 | * @author Oliver Drotbohm
29 | */
30 | @Transactional
31 | @Service
32 | @RequiredArgsConstructor
33 | public class OrderManagement {
34 |
35 | private final OrderRepository orders;
36 |
37 | public Order create(CustomerIdentifier customerId) {
38 | return new Order(customerId);
39 | }
40 |
41 | public Order complete(Order order) {
42 | return orders.save(order.complete());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/customer/Customer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.customer;
17 |
18 | import lombok.Getter;
19 |
20 | import java.util.UUID;
21 |
22 | import org.jmolecules.ddd.types.AggregateRoot;
23 | import org.jmolecules.ddd.types.Identifier;
24 |
25 | import com.example.app.customer.Customer.CustomerIdentifier;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | @Getter
31 | public class Customer implements AggregateRoot {
32 |
33 | private final CustomerIdentifier id;
34 | private final String address;
35 |
36 | public Customer(String address) {
37 |
38 | this.id = new CustomerIdentifier(UUID.randomUUID());
39 | this.address = address;
40 | }
41 |
42 | public record CustomerIdentifier(UUID id) implements Identifier {}
43 | }
44 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.transaction.Transactional;
19 | import lombok.RequiredArgsConstructor;
20 |
21 | import org.jmolecules.ddd.annotation.Service;
22 |
23 | import com.example.app.customer.Customer.CustomerIdentifier;
24 |
25 | /**
26 | * The primary application service of the order module.
27 | *
28 | * @author Oliver Drotbohm
29 | */
30 | @Transactional
31 | @Service
32 | @RequiredArgsConstructor
33 | public class OrderManagement {
34 |
35 | private final OrderRepository orders;
36 |
37 | public Order create(CustomerIdentifier customerId) {
38 | return new Order(customerId);
39 | }
40 |
41 | public Order complete(Order order) {
42 | return orders.save(order.complete());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.jmolecules.ddd.annotation.Service;
21 | import org.springframework.modulith.events.ApplicationModuleListener;
22 |
23 | import com.example.app.order.Order.OrderCompleted;
24 |
25 | /**
26 | * The primary application service for the inventory module.
27 | *
28 | * @author Oliver Drotbohm
29 | */
30 | @Service
31 | @RequiredArgsConstructor
32 | public class Inventory {
33 |
34 | @SuppressWarnings("unused") //
35 | private final InventoryRepository repository;
36 |
37 | /**
38 | * Updates the stock for all line items contained in the order.
39 | */
40 | @ApplicationModuleListener
41 | void on(OrderCompleted order) {
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.jmolecules.ddd.annotation.Service;
21 | import org.springframework.modulith.events.ApplicationModuleListener;
22 |
23 | import com.example.app.order.Order.OrderCompleted;
24 |
25 | /**
26 | * The primary application service for the inventory module.
27 | *
28 | * @author Oliver Drotbohm
29 | */
30 | @Service
31 | @RequiredArgsConstructor
32 | public class Inventory {
33 |
34 | @SuppressWarnings("unused") //
35 | private final InventoryRepository repository;
36 |
37 | /**
38 | * Updates the stock for all line items contained in the order.
39 | */
40 | @ApplicationModuleListener
41 | void on(OrderCompleted order) {
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/inventory/InventoryItemRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import java.util.Optional;
19 |
20 | import org.jmolecules.ddd.types.Association;
21 | import org.springframework.data.repository.CrudRepository;
22 |
23 | import com.example.app.catalog.Product;
24 | import com.example.app.catalog.Product.ProductIdentifier;
25 | import com.example.app.inventory.InventoryItem.InventoryItemIdentifier;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | public interface InventoryItemRepository extends CrudRepository {
31 |
32 | Optional findByProduct(Association association);
33 |
34 | default Optional findByProductIdentifier(ProductIdentifier identifier) {
35 | return findByProduct(Association.forId(identifier));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/test/java/com/example/app/orders/OrdersIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.springframework.context.annotation.Import;
22 | import org.springframework.modulith.test.ApplicationModuleTest;
23 | import org.springframework.modulith.test.Scenario;
24 |
25 | import com.example.app.Infrastructure;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | @ApplicationModuleTest
31 | @RequiredArgsConstructor
32 | @Import(Infrastructure.class)
33 | class OrdersIntegrationTests {
34 |
35 | private final OrderManagement orders;
36 |
37 | @Test
38 | void testName(Scenario scenario) {
39 |
40 | scenario.stimulate(orders::complete)
41 | .andWaitForEventOfType(OrderCompleted.class)
42 | .toArrive();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/java/com/example/app/orders/OrdersIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.springframework.context.annotation.Import;
22 | import org.springframework.modulith.test.ApplicationModuleTest;
23 | import org.springframework.modulith.test.Scenario;
24 |
25 | import com.example.app.Infrastructure;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | @ApplicationModuleTest
31 | @RequiredArgsConstructor
32 | @Import(Infrastructure.class)
33 | class OrdersIntegrationTests {
34 |
35 | private final OrderManagement orders;
36 |
37 | @Test
38 | void testName(Scenario scenario) {
39 |
40 | scenario.stimulate(orders::complete)
41 | .andWaitForEventOfType(OrderCompleted.class)
42 | .toArrive();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/order/EmailSender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import lombok.extern.slf4j.Slf4j;
19 |
20 | import java.util.UUID;
21 |
22 | import org.springframework.modulith.events.ApplicationModuleListener;
23 | import org.springframework.stereotype.Component;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @Slf4j
29 | @Component
30 | class EmailSender {
31 |
32 | @ApplicationModuleListener
33 | void on(OrderCompleted event) {
34 | sendEmailFor(event.orderIdentifier());
35 | }
36 |
37 | void sendEmailFor(UUID orderIdentifier) {
38 |
39 | log.info("Sending email for order {}.", orderIdentifier);
40 |
41 | try {
42 | Thread.sleep(1000);
43 | } catch (InterruptedException o_O) {}
44 |
45 | // throw new RuntimeException();
46 |
47 | log.info("Email sent for order {}.", orderIdentifier);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/00-introduction/000-article-the-domain.adoc:
--------------------------------------------------------------------------------
1 | [[introduction.domain]]
2 | = The domain
3 | :imagesdir: ../src/docs/asciidoc/images
4 |
5 | The example we are going to use is rooted in the e-commerce domain.
6 | As the focus of Spring Modulith is creating a high-level functional structure and implementing and testing the interaction between the individual parts, we don't need to exhaustively cover the entire domain but will rather focus on the following arrangement:
7 |
8 | * A catalog that contains products, primarily consisting of a description and a price.
9 | * An order management module that contains orders consisting of line items referring to the products contained in the catalog.
10 | * An inventory management that keeps track of the stock for each product.
11 |
12 | .Our E-Commerce Domain
13 |
14 | ifndef::educates[]
15 | image::domain.png[width=500, align="center"]
16 | endif::[]
17 | ifdef::educates[]
18 | [source, subs="attributes+"]
19 | ----
20 | 
21 | ----
22 | endif::[]
23 |
24 | The primary use case we will investigate in its implications on both the structural, consistency and interaction arrangement is the following: when an order is completed (i.e., flips a certain state), a variety of functionality will have to be triggered:
25 |
26 | * The inventory needs to update its stock to reflect the products referred to by the items contained in the order leaving the warehouse.
27 | * An email notification needs to be sent out to the customer.
28 | * A customer loyalty program needs to record bonus points reflecting the total value of the order.
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/src/test/java/com/example/app/inventory/InventoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import java.util.UUID;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.springframework.context.annotation.Import;
22 | import org.springframework.modulith.test.ApplicationModuleTest;
23 | import org.springframework.modulith.test.Scenario;
24 |
25 | import com.example.app.Infrastructure;
26 | import com.example.app.inventory.Inventory.InventoryUpdated;
27 | import com.example.app.orders.OrderCompleted;
28 |
29 | /**
30 | * @author Oliver Drotbohm
31 | */
32 | @ApplicationModuleTest
33 | @Import(Infrastructure.class)
34 | class InventoryIntegrationTests {
35 |
36 | @Test
37 | void updatesInventoryOnOrderCompletion(Scenario scenario) {
38 |
39 | scenario.publish(() -> new OrderCompleted(UUID.randomUUID()))
40 | .andWaitForEventOfType(InventoryUpdated.class)
41 | .toArrive();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/orders/OrderRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import java.util.Optional;
19 |
20 | import org.jmolecules.ddd.types.Association;
21 | import org.springframework.data.jpa.repository.Query;
22 | import org.springframework.data.repository.CrudRepository;
23 |
24 | import com.example.app.catalog.Product;
25 | import com.example.app.catalog.Product.ProductIdentifier;
26 | import com.example.app.orders.Order.OrderIdentifier;
27 |
28 | /**
29 | * @author Oliver Drotbohm
30 | */
31 | public interface OrderRepository extends CrudRepository {
32 |
33 | default Optional findByProductIdentifier(ProductIdentifier identifier) {
34 | return findByProductIdentifier(Association.forId(identifier));
35 | }
36 |
37 | @Query("select o from Order o join fetch o.lineItems i where i.product = :association")
38 | Optional findByProductIdentifier(Association association);
39 | }
40 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/test/java/com/example/app/inventory/InventoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.springframework.context.annotation.Import;
22 | import org.springframework.modulith.test.ApplicationModuleTest;
23 | import org.springframework.modulith.test.Scenario;
24 |
25 | import com.example.app.Infrastructure;
26 | import com.example.app.inventory.Inventory.InventoryUpdated;
27 |
28 | /**
29 | * @author Oliver Drotbohm
30 | */
31 | @ApplicationModuleTest
32 | @Import(Infrastructure.class)
33 | @RequiredArgsConstructor
34 | class InventoryIntegrationTests {
35 |
36 | private final Inventory inventory;
37 |
38 | @Test
39 | void updatesInventoryOnOrderCompletion(Scenario scenario) {
40 |
41 | scenario.stimulate(() -> inventory.update())
42 | .andWaitForEventOfType(InventoryUpdated.class)
43 | .toArrive();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/src/test/java/com/example/app/Infrastructure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.test.context.TestConfiguration;
19 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
20 | import org.springframework.context.annotation.Bean;
21 | import org.testcontainers.containers.PostgreSQLContainer;
22 | import org.testcontainers.kafka.KafkaContainer;
23 | import org.testcontainers.utility.DockerImageName;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @TestConfiguration
29 | @SuppressWarnings("resource")
30 | public class Infrastructure {
31 |
32 | @Bean
33 | @ServiceConnection
34 | PostgreSQLContainer> postgresContainer() {
35 | return new PostgreSQLContainer<>("postgres:latest");
36 | }
37 |
38 | @Bean
39 | @ServiceConnection
40 | KafkaContainer kafkaContainer() {
41 | return new KafkaContainer(DockerImageName.parse("apache/kafka:latest")).withReuse(true);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/src/test/java/com/example/app/Infrastructure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app;
17 |
18 | import org.springframework.boot.test.context.TestConfiguration;
19 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
20 | import org.springframework.context.annotation.Bean;
21 | import org.testcontainers.containers.PostgreSQLContainer;
22 | import org.testcontainers.kafka.KafkaContainer;
23 | import org.testcontainers.utility.DockerImageName;
24 |
25 | /**
26 | * @author Oliver Drotbohm
27 | */
28 | @TestConfiguration
29 | public class Infrastructure {
30 |
31 | @Bean
32 | @ServiceConnection
33 | PostgreSQLContainer> postgresContainer() {
34 | return new PostgreSQLContainer<>("postgres:latest");
35 | }
36 |
37 | @Bean
38 | @ServiceConnection
39 | @SuppressWarnings("resource")
40 | KafkaContainer kafkaContainer() {
41 | return new KafkaContainer(DockerImageName.parse("apache/kafka:latest")).withReuse(true);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import lombok.RequiredArgsConstructor;
19 | import lombok.extern.slf4j.Slf4j;
20 |
21 | import java.util.UUID;
22 |
23 | import org.springframework.context.ApplicationEventPublisher;
24 | import org.springframework.stereotype.Service;
25 | import org.springframework.transaction.annotation.Transactional;
26 |
27 | /**
28 | * @author Oliver Drotbohm
29 | */
30 | @Slf4j
31 | @Service
32 | @Transactional
33 | @RequiredArgsConstructor
34 | public class OrderManagement {
35 |
36 | private final OrderRepository orders;
37 | private final ApplicationEventPublisher events;
38 |
39 | public Order findById(UUID id) {
40 | return orders.findById(id).orElse(null);
41 | }
42 |
43 | public void complete(Order order) {
44 |
45 | orders.save(order.complete());
46 |
47 | events.publishEvent(new OrderCompleted(order.getId()));
48 |
49 | log.info("Finish order completion.");
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/src/main/java/com/example/app/order/OrderManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import lombok.RequiredArgsConstructor;
19 | import lombok.extern.slf4j.Slf4j;
20 |
21 | import java.util.UUID;
22 |
23 | import org.springframework.stereotype.Service;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | import com.example.app.inventory.Inventory;
27 |
28 | /**
29 | * @author Oliver Drotbohm
30 | */
31 | @Slf4j
32 | @Service
33 | @Transactional
34 | @RequiredArgsConstructor
35 | public class OrderManagement {
36 |
37 | private final OrderRepository orders;
38 | private final EmailSender emails;
39 | private final Inventory inventory;
40 |
41 | public Order findById(UUID id) {
42 | return orders.findById(id).orElse(null);
43 | }
44 |
45 | public void complete(Order order) {
46 |
47 | orders.save(order.complete());
48 |
49 | inventory.updateStockFor(order);
50 | emails.sendEmailFor(order.getId());
51 |
52 | log.info("Finish order completion.");
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/src/main/java/com/example/app/inventory/Inventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.RequiredArgsConstructor;
19 | import lombok.extern.slf4j.Slf4j;
20 |
21 | import org.springframework.modulith.events.ApplicationModuleListener;
22 | import org.springframework.stereotype.Service;
23 | import org.springframework.transaction.annotation.Transactional;
24 |
25 | import com.example.app.order.Order;
26 | import com.example.app.order.OrderCompleted;
27 | import com.example.app.order.OrderManagement;
28 |
29 | /**
30 | * @author Oliver Drotbohm
31 | */
32 | @Slf4j
33 | @Service
34 | @Transactional
35 | @RequiredArgsConstructor
36 | public class Inventory {
37 |
38 | private final OrderManagement orders;
39 |
40 | @ApplicationModuleListener
41 | void on(OrderCompleted event) {
42 | updateStockFor(orders.findById(event.orderIdentifier()));
43 | }
44 |
45 | public void updateStockFor(Order order) {
46 |
47 | log.info("Updating stock for order {}.", order.getId());
48 |
49 | // throw new RuntimeException();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/test/java/com/example/app/orders/OrderRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import jakarta.persistence.EntityManager;
21 | import jakarta.transaction.Transactional;
22 |
23 | import java.util.UUID;
24 |
25 | import org.junit.jupiter.api.Test;
26 | import org.springframework.beans.factory.annotation.Autowired;
27 | import org.springframework.boot.test.context.SpringBootTest;
28 |
29 | import com.example.app.catalog.Product.ProductIdentifier;
30 |
31 | /**
32 | * @author Oliver Drotbohm
33 | */
34 | @SpringBootTest
35 | @Transactional
36 | class OrderRepositoryIntegrationTests {
37 |
38 | @Autowired OrderRepository repository;
39 | @Autowired EntityManager em;
40 |
41 | @Test
42 | void createsNewOrder() {
43 |
44 | var productIdentifier = new ProductIdentifier(UUID.randomUUID());
45 |
46 | var order = new Order().add(productIdentifier, 42);
47 |
48 | var result = repository.save(order);
49 |
50 | em.flush();
51 |
52 | assertThat(repository.findByProductIdentifier(productIdentifier)).hasValue(result);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/20-designing-application-modules/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | designing-application-modules-complete
7 |
8 |
9 | de.odrotbohm.smdd
10 | designing-application-modules
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 2 - Designing Application Modules - Complete
16 |
17 |
18 |
19 |
20 | org.springframework.modulith
21 | spring-modulith-bom
22 | ${spring-modulith.version}
23 | pom
24 | import
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 |
39 |
40 | org.springframework.modulith
41 | spring-modulith-api
42 |
43 |
44 |
45 | org.springframework.modulith
46 | spring-modulith-starter-test
47 | test
48 |
49 |
50 |
51 | org.projectlombok
52 | lombok
53 | provided
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/20-designing-application-modules/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | designing-application-modules-initial
7 |
8 |
9 | de.odrotbohm.smdd
10 | designing-application-modules
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 2 - Designing Application Modules - Initial
16 |
17 |
18 |
19 |
20 | org.springframework.modulith
21 | spring-modulith-bom
22 | ${spring-modulith.version}
23 | pom
24 | import
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 |
39 |
40 | org.springframework.modulith
41 | spring-modulith-api
42 |
43 |
44 |
45 | org.springframework.modulith
46 | spring-modulith-starter-test
47 | test
48 |
49 |
50 |
51 | org.projectlombok
52 | lombok
53 | provided
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/catalog/Product.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.catalog;
17 |
18 | import lombok.Getter;
19 |
20 | import java.math.BigDecimal;
21 | import java.util.UUID;
22 |
23 | import org.jmolecules.ddd.types.AggregateRoot;
24 | import org.jmolecules.ddd.types.Identifier;
25 | import org.jmolecules.event.types.DomainEvent;
26 | import org.springframework.data.domain.AbstractAggregateRoot;
27 |
28 | import com.example.app.catalog.Product.ProductIdentifier;
29 |
30 | /**
31 | * @author Oliver Drotbohm
32 | */
33 | @Getter
34 | public class Product extends AbstractAggregateRoot implements AggregateRoot {
35 |
36 | private final ProductIdentifier id;
37 | private String name;
38 | private BigDecimal price;
39 |
40 | public Product(String name, BigDecimal price) {
41 |
42 | this.id = new ProductIdentifier(UUID.randomUUID());
43 | this.name = name;
44 | this.price = price;
45 |
46 | registerEvent(new ProductAdded(id));
47 | }
48 |
49 | public record ProductIdentifier(UUID productId) implements Identifier {}
50 |
51 | public record ProductAdded(ProductIdentifier product) implements DomainEvent {}
52 | }
53 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/test/java/com/example/app/catalog/ProductRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.catalog;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import java.math.BigDecimal;
21 |
22 | import org.junit.jupiter.api.Test;
23 | import org.springframework.beans.factory.annotation.Autowired;
24 | import org.springframework.boot.test.context.SpringBootTest;
25 | import org.springframework.test.context.event.ApplicationEvents;
26 | import org.springframework.test.context.event.RecordApplicationEvents;
27 | import org.springframework.transaction.annotation.Transactional;
28 |
29 | import com.example.app.catalog.Product.ProductAdded;
30 |
31 | /**
32 | * @author Oliver Drotbohm
33 | */
34 | @SpringBootTest
35 | @Transactional
36 | @RecordApplicationEvents
37 | class ProductRepositoryIntegrationTests {
38 |
39 | @Autowired ProductRepository products;
40 |
41 | @Test
42 | void createsProduct(ApplicationEvents events) {
43 |
44 | var product = products.save(new Product("Some product.", new BigDecimal(99.99)));
45 |
46 | assertThat(products.findByName(product.getName())).hasValue(product);
47 | assertThat(events.stream(ProductAdded.class)
48 | .filter(it -> it.product().equals(product.getId())))
49 | .isNotEmpty();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/30-event-based-integration/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | event-based-integration-initial
7 |
8 |
9 | de.odrotbohm.smdd
10 | event-based-integration
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 3 - Event-Based Integration - Initial
16 |
17 |
18 |
19 |
20 | org.springframework.modulith
21 | spring-modulith-bom
22 | ${spring-modulith.version}
23 | pom
24 | import
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-data-jpa
35 |
36 |
37 |
38 | com.h2database
39 | h2
40 | runtime
41 |
42 |
43 |
44 |
45 |
46 | org.springframework.modulith
47 | spring-modulith-api
48 |
49 |
50 |
51 | org.projectlombok
52 | lombok
53 | provided
54 |
55 |
56 |
57 | org.springframework.modulith
58 | spring-modulith-starter-test
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/orders/LineItem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import lombok.Getter;
19 |
20 | import java.util.UUID;
21 |
22 | import org.jmolecules.ddd.types.Association;
23 | import org.jmolecules.ddd.types.Entity;
24 | import org.jmolecules.ddd.types.Identifier;
25 | import org.springframework.lang.Nullable;
26 |
27 | import com.example.app.catalog.Product;
28 | import com.example.app.catalog.Product.ProductIdentifier;
29 | import com.example.app.orders.LineItem.LineItemIdentifier;
30 |
31 | /**
32 | * @author Oliver Drotbohm
33 | */
34 | @Getter
35 | public class LineItem implements Entity {
36 |
37 | private final LineItemIdentifier id;
38 | private Association product;
39 | private @Nullable String description;
40 | private long amount;
41 |
42 | LineItem(ProductIdentifier productIdentifier, long amount) {
43 |
44 | this.id = new LineItemIdentifier(UUID.randomUUID());
45 | this.product = Association.forId(productIdentifier);
46 | this.amount = amount;
47 | }
48 |
49 | public boolean belongsToProduct(ProductIdentifier identifier) {
50 | return true; // this.product.pointsTo(identifier);
51 | }
52 |
53 | public LineItem increaseQuantityBy(long amount) {
54 |
55 | this.amount = this.amount + amount;
56 |
57 | return this;
58 | }
59 |
60 | public record LineItemIdentifier(UUID lineItemId) implements Identifier {}
61 | }
62 |
--------------------------------------------------------------------------------
/.educates/prep4educates.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | script="$0"
4 | scriptDir="$(dirname "$script")"
5 | basedir="target/educates"
6 | springModulithVersion=$($scriptDir/../mvnw help:evaluate -Dexpression=spring-modulith.version -q -DforceStdout)
7 |
8 | rm -rf $basedir
9 |
10 | # Scan folders starting with two digits
11 | for dir in [0-9][0-9]*/; do
12 |
13 | # [[ $(basename $dir) == "00-introduction" ]] && continue
14 |
15 | # Move setup files
16 | target=${basedir}/workshops/${dir}
17 | mkdir -p $target
18 | cp -r .educates/files/* $target
19 |
20 |
21 | # Find all AsciiDoc files recursively
22 | find $dir -name "[0-9][0-9][0-9]*.adoc" -type f | while read -r file; do
23 |
24 | filename=$(basename "$file" .adoc)
25 |
26 | if [[ $filename =~ .*-article-.* ]]; then
27 | targetDir="${basedir}/${dir}"
28 | targetFile="content.md"
29 | isArticle=true
30 | else
31 | targetDir="${basedir}/workshops/${dir}workshop/content"
32 | targetFile="${filename}.md"
33 | isArticle=false
34 | fi
35 |
36 | # Create folder
37 | mkdir -p $targetDir
38 |
39 |
40 | # Convert AsciiDoc to DocBook using Asciidoctor
41 | asciidoctor -b docbook -d book \
42 | -a educates \
43 | -a tabsize=4 \
44 | -a imagesdir=images \
45 | -a spring-modulith-version=$springModulithVersion \
46 | -o - "$file" | \
47 |
48 | # Convert DocBook to Markdown using Pandoc
49 | # -s to keep the primary headline
50 | pandoc -s -f docbook -t markdown -o "${targetDir}/${targetFile}"
51 |
52 | done
53 |
54 | done
55 |
56 | # Copy images to target folder
57 | asciidoctorbase="src/docs/asciidoc"
58 | imagesdir="images"
59 | files=$(find $basedir -type f -name "*.md")
60 |
61 | # Loop through each file
62 | for file in $files; do
63 |
64 | target=$(dirname $file)
65 |
66 | # Search for image tags and extract src attribute value
67 | while IFS= read -r line; do
68 | if [[ $line =~ !\[img\]\((.*)\) ]]; then
69 | mkdir $target/$imagesdir
70 | cp "${asciidoctorbase}/${BASH_REMATCH[1]}" "${target}/${BASH_REMATCH[1]}"
71 | fi
72 | done < "$file"
73 |
74 | done
75 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-inventory/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-initial-inventory
7 |
8 | 7 - Splitup - Initial - Inventory
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup-initial
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 | org.jmolecules.integrations
21 | jmolecules-starter-ddd
22 |
23 |
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-jdbc
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-json
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.modulith
40 | spring-modulith-starter-test
41 | test
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.projectlombok
53 | lombok
54 |
55 |
56 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/20-designing-application-modules/203-lab-application-module-relationships.adoc:
--------------------------------------------------------------------------------
1 | [[module-design.relationships]]
2 | = 🧑💻 Establishing relationships between modules
3 |
4 | [[module-design.relationships.objectives]]
5 | == 🎯 Objectives
6 |
7 | You'll learn how to…
8 |
9 | * … establish relationships between modules via Spring bean references
10 | * … detect invalid dependencies via a JUnit-based architectural fitness function
11 |
12 | [[module-design.relationships.managing-type-relationships]]
13 | == 👣 Managing type relationships
14 |
15 | . Create an application module package `inventory`.
16 | . Add an application service `Inventory` inside that package.
17 | +
18 | [source, java]
19 | ----
20 | package com.example.app.inventory;
21 |
22 | import lombok.RequiredArgsConstructor;
23 |
24 | import org.springframework.stereotype.Component;
25 |
26 | @Component
27 | @RequiredArgsConstructor
28 | public class Inventory {
29 | }
30 | ----
31 |
32 | . Run modularity tests and see the module listed including the `Inventory` component.
33 | . In `OrderManagement` add a dependency to the Inventory.
34 | +
35 | [source, java]
36 | ----
37 | package com.example.app.order;
38 |
39 | import lombok.RequiredArgsConstructor;
40 |
41 | import org.springframework.stereotype.Component;
42 |
43 | import com.example.app.inventory.Inventory;
44 |
45 | @Component
46 | @RequiredArgsConstructor
47 | public class OrderManagement {
48 |
49 | private final Inventory inventory;
50 | }
51 | ----
52 |
53 | . Run the modularity tests and see how the model now reflects the cross-application-module dependency we introduced.
54 | +
55 | [source, text]
56 | ----
57 | # Inventory
58 | > Logical name: inventory
59 | > Base package: com.example.app.inventory
60 | > Direct module dependencies: order
61 | > Spring beans:
62 | + ….Inventory
63 | ----
64 |
65 | . Introduce a dependency from the `Inventory` to the `OrderManagement`.
66 | +
67 | [source, java]
68 | ----
69 | package com.example.app.inventory;
70 |
71 | import lombok.RequiredArgsConstructor;
72 |
73 | import org.springframework.stereotype.Component;
74 |
75 | import com.example.app.order.OrderManagement;
76 |
77 | @Component
78 | @RequiredArgsConstructor
79 | public class Inventory {
80 |
81 | private final OrderManagement orders;
82 | }
83 | ----
84 |
85 | . Re-run the modularity test and see it fail. -> cyclic dependency.
86 |
--------------------------------------------------------------------------------
/30-event-based-integration/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | event-based-integration-complete
7 |
8 |
9 | de.odrotbohm.smdd
10 | event-based-integration
11 | 1.0-SNAPSHOT
12 | ../pom.xml
13 |
14 |
15 | 3 - Event-Based Integration - Complete
16 |
17 |
18 |
19 |
20 | org.jmolecules
21 | jmolecules-bom
22 | ${jmolecules.version}
23 | import
24 | pom
25 |
26 |
27 | org.springframework.modulith
28 | spring-modulith-bom
29 | ${spring-modulith.version}
30 | pom
31 | import
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-data-jpa
41 |
42 |
43 |
44 | com.h2database
45 | h2
46 | runtime
47 |
48 |
49 |
50 |
51 |
52 | org.springframework.modulith
53 | spring-modulith-api
54 |
55 |
56 |
57 | org.springframework.modulith
58 | spring-modulith-starter-jpa
59 |
60 |
61 |
62 | org.projectlombok
63 | lombok
64 | provided
65 |
66 |
67 |
68 | org.springframework.modulith
69 | spring-modulith-starter-test
70 | test
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/inventory/InventoryItem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.inventory;
17 |
18 | import lombok.Getter;
19 |
20 | import java.util.UUID;
21 |
22 | import org.jmolecules.ddd.types.AggregateRoot;
23 | import org.jmolecules.ddd.types.Association;
24 | import org.jmolecules.ddd.types.Identifier;
25 | import org.jmolecules.event.types.DomainEvent;
26 | import org.springframework.data.domain.AbstractAggregateRoot;
27 |
28 | import com.example.app.catalog.Product;
29 | import com.example.app.catalog.Product.ProductIdentifier;
30 | import com.example.app.inventory.InventoryItem.InventoryItemIdentifier;
31 |
32 | /**
33 | * @author Oliver Drotbohm
34 | */
35 | @Getter
36 | public class InventoryItem extends AbstractAggregateRoot
37 | implements AggregateRoot {
38 |
39 | private final InventoryItemIdentifier id;
40 | private final Association product;
41 | private long amount;
42 |
43 | InventoryItem(ProductIdentifier productIdentifier, long amount) {
44 |
45 | this.id = new InventoryItemIdentifier(UUID.randomUUID());
46 | this.product = Association.forId(productIdentifier);
47 | this.amount = amount;
48 | }
49 |
50 | InventoryItem refillBy(long amount) {
51 |
52 | this.amount = this.amount + amount;
53 |
54 | return this;
55 | }
56 |
57 | InventoryItem reduceStockBy(long amount) {
58 |
59 | if (this.amount < amount) {
60 | registerEvent(new OutOfStock(product));
61 | }
62 |
63 | this.amount = this.amount - amount;
64 |
65 | return this;
66 | }
67 |
68 | public record InventoryItemIdentifier(UUID itemId) implements Identifier {}
69 |
70 | public record OutOfStock(Association product) implements DomainEvent {}
71 | }
72 |
--------------------------------------------------------------------------------
/00-introduction/00-introduction.adoc:
--------------------------------------------------------------------------------
1 | [preface]
2 | [[introduction]]
3 | = Introduction
4 |
5 | [[introduction.logistics]]
6 | == 📋 Logistics
7 |
8 | === Working with the document
9 |
10 | We use the following icons to represent different parts of the document
11 |
12 | * 🧑💻 -- A lab.
13 | * 🎯 -- Describes the learning goals of the lab.
14 | * 👣 -- Describes a set of steps to complete a topical lab.
15 | * 📖 -- Describes a section of contextual content, often referring to sections of the slide deck.
16 | * 💡 -- Summarizes the lab and often include ideas of how to take the code of the lab further.
17 |
18 | ifndef::educates[]
19 | [WARNING]
20 | endif::[]
21 | ifdef::educates[]
22 | [quote]
23 | ____
24 | **Warning** +
25 | endif::[]
26 | Most of the steps include fractions of the code to be added to a project.
27 | The code samples often have important parts folded (indicated by the `…` icon in the lower right corner if you hover over the code block).
28 | Be sure to use the clipboard icon to copy the whole content.
29 | ifdef::educates[]
30 | ____
31 | endif::[]
32 |
33 | ifndef::educates[]
34 | include::000-article-the-domain.adoc[leveloffset=+1]
35 | endif::[]
36 |
37 | [[introduction.sample-code]]
38 | == 🧑💻 Sample Code
39 |
40 | The sample code can be found in https://github.com/odrotbohm/spring-modulith-deep-dive[this GitHub repository].
41 | It consists of individual folders per lab, each of them containing an `initial` folder that contains the playground to start with.
42 | The lab descriptions in the document here help you understand the goal and walk you through a set of steps to explore a certain piece of functionality of Spring Modulith in the context of the domain.
43 | If you get stuck or need some inspiration, you can check the content of the `complete` folder as it contains the project in the shape the individual steps should have guided you to.
44 |
45 | ifndef::educates[]
46 | [[introduction.sample-code.prerequisites]]
47 | === 💼 Prerequisites
48 | * Git
49 | * Java 17
50 | * IDE (IDEA, Eclipse)
51 | * Docker
52 |
53 | [source, bash]
54 | ----
55 | $ git clone https://github.com/odrotbohm/spring-modulith-deep-dive
56 | $ cd spring-modulith-deep-dive
57 | ----
58 |
59 | [[introduction.sample-code.setup]]
60 | === 👣 Setup
61 |
62 | [source, bash]
63 | ----
64 | $ git clone https://github.com/odrotbohm/spring-modulith-deep-dive
65 | $ cd spring-modulith-deep-dive
66 | $ ./mvnw clean verify
67 | ----
68 | endif::[]
69 |
70 | ////
71 | [[introduction.spring-cli]]
72 | == 🖥️ Spring CLI
73 | ////
74 |
75 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/src/main/java/com/example/app/orders/Order.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.orders;
17 |
18 | import jakarta.persistence.Table;
19 | import lombok.AccessLevel;
20 | import lombok.AllArgsConstructor;
21 | import lombok.Getter;
22 | import lombok.With;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 | import java.util.UUID;
27 |
28 | import org.jmolecules.ddd.types.AggregateRoot;
29 | import org.jmolecules.ddd.types.Identifier;
30 | import org.jmolecules.event.types.DomainEvent;
31 | import org.springframework.data.domain.AbstractAggregateRoot;
32 |
33 | import com.example.app.catalog.Product.ProductIdentifier;
34 | import com.example.app.orders.Order.OrderIdentifier;
35 |
36 | /**
37 | * @author Oliver Drotbohm
38 | */
39 | @Table(name = "ORDERS")
40 | @Getter
41 | @AllArgsConstructor(access = AccessLevel.PRIVATE)
42 | public class Order extends AbstractAggregateRoot implements AggregateRoot {
43 |
44 | private final OrderIdentifier id;
45 | private final List lineItems;
46 | private final @With Status status;
47 |
48 | Order() {
49 |
50 | this.id = new OrderIdentifier(UUID.randomUUID());
51 | this.lineItems = new ArrayList<>();
52 | this.status = Status.SUBMITTED;
53 | }
54 |
55 | public Order add(ProductIdentifier identifier, long amount) {
56 |
57 | lineItems.stream()
58 | .filter(it -> it.belongsToProduct(identifier))
59 | .findFirst()
60 | .ifPresentOrElse(
61 | it -> it.increaseQuantityBy(amount),
62 | () -> lineItems.add(new LineItem(identifier, amount)));
63 |
64 | return this;
65 | }
66 |
67 | Order complete() {
68 |
69 | return withStatus(Status.COMPLETED) //
70 | .andEventsFrom(this) //
71 | .andEvent(new OrderCompleted(id));
72 | }
73 |
74 | public enum Status {
75 | SUBMITTED, COMPLETED;
76 | }
77 |
78 | public record OrderIdentifier(UUID orderId) implements Identifier {}
79 |
80 | public record OrderCompleted(OrderIdentifier orderIdentifier) implements DomainEvent {}
81 | }
82 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-ecommerce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-complete-ecommerce
7 |
8 | 7 - Splitup - Complete - E-Commerce
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup-complete
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.projectlombok
23 | lombok
24 |
25 |
26 |
27 |
28 |
29 | org.jmolecules.integrations
30 | jmolecules-starter-ddd
31 |
32 |
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-web
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-jdbc
43 |
44 |
45 |
46 |
47 |
48 | org.springframework.modulith
49 | spring-modulith-starter-jdbc
50 |
51 |
52 |
53 | org.springframework.modulith
54 | spring-modulith-starter-test
55 | test
56 |
57 |
58 |
59 | org.springframework.modulith
60 | spring-modulith-events-kafka
61 | runtime
62 |
63 |
64 |
65 |
66 |
67 | org.postgresql
68 | postgresql
69 | runtime
70 |
71 |
72 |
73 | org.testcontainers
74 | postgresql
75 | test
76 |
77 |
78 |
79 |
80 |
81 | org.testcontainers
82 | kafka
83 | test
84 |
85 |
86 |
87 | org.springframework.boot
88 | spring-boot-testcontainers
89 | test
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/70-splitup/complete/splitup-complete-inventory/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-complete-inventory
7 |
8 | 7 - Splitup - Complete - Inventory
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup-complete
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-json
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-jdbc
29 | runtime
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-test
35 | test
36 |
37 |
38 |
39 |
40 |
41 | org.springframework.modulith
42 | spring-modulith-starter-jdbc
43 |
44 |
45 |
46 | org.springframework.modulith
47 | spring-modulith-events-kafka
48 |
49 |
50 |
51 | org.springframework.modulith
52 | spring-modulith-starter-test
53 | test
54 |
55 |
56 |
57 |
58 |
59 | org.projectlombok
60 | lombok
61 |
62 |
63 |
64 |
65 |
66 | org.postgresql
67 | postgresql
68 | runtime
69 |
70 |
71 |
72 | org.testcontainers
73 | postgresql
74 | test
75 |
76 |
77 |
78 |
79 |
80 | org.springframework.kafka
81 | spring-kafka
82 |
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-testcontainers
87 | test
88 |
89 |
90 |
91 | org.testcontainers
92 | kafka
93 | test
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/70-splitup/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-initial
7 |
8 | 7 - Splitup - Initial
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 | splitup-initial-ecommerce
19 | splitup-initial-inventory
20 |
21 |
22 | pom
23 |
24 |
25 |
26 |
27 | org.jmolecules
28 | jmolecules-bom
29 | 2023.1.3
30 | pom
31 | import
32 |
33 |
34 | org.springframework.modulith
35 | spring-modulith-bom
36 | ${spring-modulith.version}
37 | pom
38 | import
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-maven-plugin
48 |
49 | true
50 |
51 |
52 |
53 | org.springframework.boot.experimental
54 | spring-boot-thin-layout
55 | 1.0.29.RELEASE
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | spring-milestone
65 | https://repo.spring.io/milestone
66 |
67 | false
68 |
69 |
70 |
71 | spring-snapshots
72 | https://repo.spring.io/snapshot
73 |
74 | false
75 |
76 |
77 |
78 |
79 |
80 |
81 | spring-milestone
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 | spring-snapshots
89 | https://repo.spring.io/snapshot
90 |
91 | false
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/70-splitup/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-complete
7 |
8 | 7 - Splitup - Complete
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 | splitup-complete-ecommerce
19 | splitup-complete-inventory
20 |
21 |
22 | pom
23 |
24 |
25 |
26 |
27 | org.jmolecules
28 | jmolecules-bom
29 | 2023.1.3
30 | pom
31 | import
32 |
33 |
34 | org.springframework.modulith
35 | spring-modulith-bom
36 | ${spring-modulith.version}
37 | pom
38 | import
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-maven-plugin
48 |
49 | true
50 |
51 |
52 |
53 | org.springframework.boot.experimental
54 | spring-boot-thin-layout
55 | 1.0.29.RELEASE
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | spring-milestone
65 | https://repo.spring.io/milestone
66 |
67 | false
68 |
69 |
70 |
71 | spring-snapshots
72 | https://repo.spring.io/snapshot
73 |
74 | false
75 |
76 |
77 |
78 |
79 |
80 |
81 | spring-milestone
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 | spring-snapshots
89 | https://repo.spring.io/snapshot
90 |
91 | false
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/70-splitup/initial/splitup-initial-ecommerce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | splitup-initial-ecommerce
7 |
8 | 7 - Splitup - Initial - E-Commerce
9 |
10 |
11 | de.odrotbohm.smdd
12 | splitup-initial
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.projectlombok
23 | lombok
24 |
25 |
26 |
27 |
28 |
29 | org.jmolecules.integrations
30 | jmolecules-starter-ddd
31 |
32 |
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-web
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-jdbc
43 |
44 |
45 |
46 |
47 |
48 | org.springframework.modulith
49 | spring-modulith-starter-jdbc
50 |
51 |
52 |
53 | org.springframework.modulith
54 | spring-modulith-starter-test
55 | test
56 |
57 |
58 |
59 |
60 |
61 | org.postgresql
62 | postgresql
63 | runtime
64 |
65 |
66 |
67 | org.testcontainers
68 | postgresql
69 | test
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-testcontainers
75 | test
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | net.bytebuddy
85 | byte-buddy-maven-plugin
86 | 1.14.4
87 |
88 | true
89 |
90 |
91 |
92 |
93 | transform-extended
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/60-documentation/60-documentation.adoc:
--------------------------------------------------------------------------------
1 | [[documentation]]
2 | = Documentation
3 | :toc:
4 | :source: complete/src/main/java/com/example/app
5 | :test-source: complete/src/test/java/com/example/app
6 |
7 | ifdef::educates[]
8 | [source, terminal:execute-all]
9 | ----
10 | command: cd ~/exercises && clear
11 | autostart: true
12 | hidden: true
13 | ----
14 |
15 | [source, dashboard:reload-dashboard]
16 | ----
17 | name: Editor
18 | autostart: true
19 | hidden: true
20 | ----
21 | endif::[]
22 |
23 | [[documentation.fundamentals]]
24 | == 🧑💻 Generating Application Module Documentation
25 |
26 | You'll
27 |
28 | [[documentation.fundamentals.objectives]]
29 | === 🎯 Objectives
30 |
31 | [[documentation.fundamentals.basics]]
32 | === 👣 Documentation
33 |
34 | . Replace `spring-modulith-core` artifact with `spring-modulith-starter-test`.
35 | +
36 | [source, xml, subs="attributes+"]
37 | ----
38 |
39 | org.springframework.modulith
40 | spring-modulith-starter-test
41 | {spring-modulith-version}
42 |
43 | ----
44 |
45 | . Run `./mvnw dependency:list -Dsort` to see the altered output.
46 | +
47 | [source, bash, subs="attributes+"]
48 | ----
49 | [INFO] org.springframework.modulith:spring-modulith-api:jar:{spring-modulith-version}:test -- module org.springframework.modulith.api [auto]
50 | [INFO] org.springframework.modulith:spring-modulith-core:jar:{spring-modulith-version}:test -- module org.springframework.modulith.core [auto]
51 | [INFO] org.springframework.modulith:spring-modulith-docs:jar:{spring-modulith-version}:test -- module org.springframework.modulith.docs [auto]
52 | [INFO] org.springframework.modulith:spring-modulith-events-api:jar:{spring-modulith-version}:compile -- module org.springframework.modulith.events.api [auto]
53 | [INFO] org.springframework.modulith:spring-modulith-starter-test:jar:{spring-modulith-version}:test -- module org.springframework.modulith.starter.test [auto]
54 | [INFO] org.springframework.modulith:spring-modulith-test:jar:{spring-modulith-version}:test -- module org.springframework.modulith.test [auto]
55 | ----
56 |
57 | . Alter `ApplicationModularityTests` to create an instance of `Documenter` and call `writeDocumentation()` on it:
58 | +
59 | [source, java]
60 | ----
61 | include::{test-source}/ApplicationModularityTests.java[tag=modularityTests]
62 | ----
63 |
64 | . Run the test case and see how the execution has created a folder `target/spring-modulith-docs`.
65 |
66 | [[documentation.fundamentals.configuration-properties]]
67 | === 👣 Documenting Spring Boot Configuration Properties
68 |
69 | 1. Add Spring Boot configuration properties type to project
70 | +
71 | [source, java]
72 | ----
73 | include::{source}/inventory/InventorySettings.java[]
74 | ----
75 | 2. Add configuration properties processor to project
76 | 3. Re-run `ApplicationModularityTests` and see how
77 |
78 | [[documentation.fundamentals.further-ideas]]
79 | === 💡 Further ideas
80 | * Play with the visibility of the internal components like `InventoryRepository`.
81 | How does it affect the output of documentation generation?
82 |
--------------------------------------------------------------------------------
/50-jmolecules/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | jmolecules-complete
7 |
8 | 5 - jMolecules - Complete
9 |
10 |
11 | de.odrotbohm.smdd
12 | jmolecules
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 | org.jmolecules
21 | jmolecules-bom
22 | ${jmolecules.version}
23 | import
24 | pom
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.projectlombok
33 | lombok
34 | provided
35 |
36 |
37 |
38 |
39 |
40 | org.jmolecules.integrations
41 | jmolecules-starter-ddd
42 |
43 |
44 |
45 | org.jmolecules.integrations
46 | jmolecules-archunit
47 | test
48 |
49 |
50 |
51 | com.tngtech.archunit
52 | archunit-junit5
53 | ${archunit.version}
54 | test
55 |
56 |
57 |
58 | org.springframework.boot
59 | spring-boot-starter-data-jpa
60 |
61 |
62 |
63 | com.h2database
64 | h2
65 | runtime
66 |
67 |
68 |
69 | org.jmolecules.integrations
70 | jmolecules-jpa
71 | runtime
72 |
73 |
74 |
75 | org.jmolecules.integrations
76 | jmolecules-bytebuddy-nodep
77 | provided
78 |
79 |
80 |
81 | org.springframework.boot
82 | spring-boot-starter-test
83 | test
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | net.bytebuddy
94 | byte-buddy-maven-plugin
95 | ${bytebuddy.version}
96 |
97 |
98 |
99 | transform-extended
100 |
101 |
102 |
103 |
104 | true
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/60-documentation/complete/src/main/java/com/example/app/order/Order.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.persistence.Table;
19 | import lombok.Getter;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.UUID;
24 |
25 | import org.jmolecules.ddd.types.AggregateRoot;
26 | import org.jmolecules.ddd.types.Association;
27 | import org.jmolecules.ddd.types.Entity;
28 | import org.jmolecules.ddd.types.Identifier;
29 | import org.jmolecules.event.annotation.Externalized;
30 | import org.jmolecules.event.types.DomainEvent;
31 | import org.springframework.data.domain.AbstractAggregateRoot;
32 |
33 | import com.example.app.customer.Customer;
34 | import com.example.app.customer.Customer.CustomerIdentifier;
35 | import com.example.app.order.Order.LineItem.LineItemId;
36 | import com.example.app.order.Order.OrderIdentifier;
37 |
38 | /**
39 | * An order placed by a customer.
40 | *
41 | * @author Oliver Drotbohm
42 | */
43 | @Getter
44 | @Table(name = "MyOrder")
45 | public class Order extends AbstractAggregateRoot implements AggregateRoot {
46 |
47 | private final OrderIdentifier id;
48 | private final Association customer;
49 | private Status status;
50 |
51 | private final List lineItems = new ArrayList<>();
52 |
53 | public Order(CustomerIdentifier customerId) {
54 |
55 | this.id = new OrderIdentifier(UUID.randomUUID());
56 | this.status = Status.OPEN;
57 | this.customer = Association.forId(customerId);
58 | }
59 |
60 | Order complete() {
61 |
62 | this.status = Status.COMPLETED;
63 |
64 | registerEvent(new OrderCompleted(id));
65 |
66 | return this;
67 | }
68 |
69 | Order add(LineItem item) {
70 |
71 | this.lineItems.add(item);
72 |
73 | return this;
74 | }
75 |
76 | public record OrderIdentifier(UUID id) implements Identifier {}
77 |
78 | /**
79 | * A domain event published, once an {@link Order} has been marked as completed.
80 | *
81 | * @author Oliver Drotbohm
82 | */
83 | @Externalized("orders.OrderCompleted")
84 | public record OrderCompleted(OrderIdentifier id) implements DomainEvent {}
85 |
86 | enum Status {
87 | OPEN, COMPLETED, CANCELLED;
88 | }
89 |
90 | @Getter
91 | static class LineItem implements Entity {
92 |
93 | private LineItemId id;
94 | private String description;
95 | private long amount;
96 |
97 | LineItem(String description, long amount) {
98 |
99 | this.id = new LineItemId(UUID.randomUUID());
100 | this.description = description;
101 | this.amount = amount;
102 | }
103 |
104 | record LineItemId(UUID id) implements Identifier {}
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/60-documentation/initial/src/main/java/com/example/app/order/Order.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.app.order;
17 |
18 | import jakarta.persistence.Table;
19 | import lombok.Getter;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.UUID;
24 |
25 | import org.jmolecules.ddd.types.AggregateRoot;
26 | import org.jmolecules.ddd.types.Association;
27 | import org.jmolecules.ddd.types.Entity;
28 | import org.jmolecules.ddd.types.Identifier;
29 | import org.jmolecules.event.annotation.Externalized;
30 | import org.jmolecules.event.types.DomainEvent;
31 | import org.springframework.data.domain.AbstractAggregateRoot;
32 |
33 | import com.example.app.customer.Customer;
34 | import com.example.app.customer.Customer.CustomerIdentifier;
35 | import com.example.app.order.Order.LineItem.LineItemId;
36 | import com.example.app.order.Order.OrderIdentifier;
37 |
38 | /**
39 | * An order placed by a customer.
40 | *
41 | * @author Oliver Drotbohm
42 | */
43 | @Getter
44 | @Table(name = "MyOrder")
45 | public class Order extends AbstractAggregateRoot implements AggregateRoot {
46 |
47 | private final OrderIdentifier id;
48 | private final Association customer;
49 | private Status status;
50 |
51 | private final List lineItems = new ArrayList<>();
52 |
53 | public Order(CustomerIdentifier customerId) {
54 |
55 | this.id = new OrderIdentifier(UUID.randomUUID());
56 | this.status = Status.OPEN;
57 | this.customer = Association.forId(customerId);
58 | }
59 |
60 | Order complete() {
61 |
62 | this.status = Status.COMPLETED;
63 |
64 | registerEvent(new OrderCompleted(id));
65 |
66 | return this;
67 | }
68 |
69 | Order add(LineItem item) {
70 |
71 | this.lineItems.add(item);
72 |
73 | return this;
74 | }
75 |
76 | public record OrderIdentifier(UUID id) implements Identifier {}
77 |
78 | /**
79 | * A domain event published, once an {@link Order} has been marked as completed.
80 | *
81 | * @author Oliver Drotbohm
82 | */
83 | @Externalized("orders.OrderCompleted")
84 | public record OrderCompleted(OrderIdentifier id) implements DomainEvent {}
85 |
86 | enum Status {
87 | OPEN, COMPLETED, CANCELLED;
88 | }
89 |
90 | @Getter
91 | static class LineItem implements Entity {
92 |
93 | private LineItemId id;
94 | private String description;
95 | private long amount;
96 |
97 | LineItem(String description, long amount) {
98 |
99 | this.id = new LineItemId(UUID.randomUUID());
100 | this.description = description;
101 | this.amount = amount;
102 | }
103 |
104 | record LineItemId(UUID id) implements Identifier {}
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/10-fundamentals/101-setup.adoc:
--------------------------------------------------------------------------------
1 | [[fundamentals.setup]]
2 | = 🧑💻 Spring Modulith Setup
3 |
4 | [[fundamentals.setup.objectives]]
5 | == 🎯 Objectives
6 |
7 | You'll learn how to…
8 |
9 | * … add the basic dependencies of Spring Modulith to your Spring Boot application.
10 | * … create an application module within the application.
11 | * … customize an application module's metadata.
12 |
13 | [[fundamentals.setup.steps]]
14 | == 👣 Build setup
15 |
16 | . Open `pom.xml` and add the Spring Modulith BOM in the `` section.
17 | +
18 | ifndef::educates[]
19 | [source, xml, subs="attributes+"]
20 | ----
21 |
22 | org.springframework.modulith
23 | spring-modulith-bom
24 | {spring-modulith-version}
25 | pom
26 | import
27 |
28 | ----
29 | endif::[]
30 |
31 | ifdef::educates[]
32 | [source, editor:select-matching-text]
33 | ----
34 | file: ~/exercises/pom.xml
35 | text: ""
36 | before: 0
37 | after: 4
38 | ----
39 | +
40 | [source, editor:replace-text-selection]
41 | ----
42 | file: ~/exercises/pom.xml
43 | text: |
44 |
45 |
46 |
47 | org.springframework.modulith
48 | spring-modulith-bom
49 | {spring-modulith-version}
50 | pom
51 | import
52 |
53 |
54 |
55 | ----
56 | endif::[]
57 |
58 | . Add the `org.springframework:spring-modulith-starter-test` dependency in test scope to your `pom.xml`.
59 | +
60 | ifndef::educates[]
61 | [source, xml]
62 | ----
63 |
64 | org.springframework.modulith
65 | spring-modulith-starter-test
66 | test
67 |
68 | ----
69 | endif::[]
70 |
71 | ifdef::educates[]
72 | [source, editor:select-matching-text]
73 | ----
74 | file: ~/exercises/pom.xml
75 | text: ""
76 | before: 0
77 | after: 0
78 | ----
79 | +
80 | [source, editor:replace-text-selection]
81 | ----
82 | file: ~/exercises/pom.xml
83 | text: |
84 |
85 | org.springframework.modulith
86 | spring-modulith-starter-test
87 | test
88 |
89 | ----
90 | endif::[]
91 |
92 | . Run `./mvnw dependency:list -Dsort`.
93 | +
94 | ifdef::educates[]
95 | [source, terminal:execute]
96 | ----
97 | command: mvnw dependency:list -Dsort | grep -v Download | grep modulith
98 | ----
99 | endif::[]
100 |
101 | . See how the output lists the Spring Modulith dependencies in test scope.
102 | +
103 | [source, bash, subs="attributes+"]
104 | ----
105 | [INFO] org.springframework.modulith:spring-modulith-api:jar:{spring-modulith-version}:test -- module org.springframework.modulith.api [auto]
106 | [INFO] org.springframework.modulith:spring-modulith-core:jar:{spring-modulith-version}:test -- module org.springframework.modulith.core [auto]
107 | [INFO] org.springframework.modulith:spring-modulith-docs:jar:{spring-modulith-version}:test -- module org.springframework.modulith.docs [auto]
108 | [INFO] org.springframework.modulith:spring-modulith-starter-test:jar:{spring-modulith-version}:test -- module org.springframework.modulith.starter.test [auto]
109 | [INFO] org.springframework.modulith:spring-modulith-test:jar:{spring-modulith-version}:test -- module org.springframework.modulith.test [auto]
110 | ----
111 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.odrotbohm.smdd
7 | spring-modulith-deep-dive
8 | 1.0-SNAPSHOT
9 | pom
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 4.0.0-M3
15 |
16 |
17 | Spring Modulith Deep-Dive
18 |
19 |
20 | 10-fundamentals
21 | 20-designing-application-modules
22 | 30-event-based-integration
23 | 40-integration-testing
24 | 50-jmolecules
25 | 60-documentation
26 | 70-splitup
27 |
28 |
29 |
30 | 1.4.1
31 | 1.17.8
32 | 21
33 | 2025.0.0-RC5
34 | 0.0.7
35 | 2.0.0-SNAPSHOT
36 |
37 |
38 |
39 |
40 | docs
41 |
42 | package
43 |
44 |
45 | org.asciidoctor
46 | asciidoctor-maven-plugin
47 | 3.0.0
48 |
49 |
50 | org.asciidoctor
51 | asciidoctorj-diagram
52 | 2.3.1
53 |
54 |
55 | io.spring.asciidoctor.backends
56 | spring-asciidoctor-backends
57 | ${spring-asciidoctor-backends.version}
58 |
59 |
60 |
61 |
62 |
63 |
64 | html
65 | generate-resources
66 |
67 | process-asciidoc
68 |
69 |
70 | spring-html
71 |
72 | highlight.js
73 | js/highlight
74 | github
75 |
76 |
77 |
78 |
79 |
80 |
81 | book
82 |
83 | shared
84 | font
85 | false
86 | images
87 | ${spring-modulith.version}
88 | 3
89 |
90 |
91 | asciidoctor-diagram
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | spring-milestone
104 | https://repo.spring.io/milestone
105 |
106 | false
107 |
108 |
109 |
110 | spring-snapshots
111 | https://repo.spring.io/snapshot
112 |
113 | false
114 |
115 |
116 |
117 |
118 |
119 |
120 | spring-milestone
121 | https://repo.spring.io/milestone
122 |
123 | false
124 |
125 |
126 |
127 | spring-snapshots
128 | https://repo.spring.io/snapshot
129 |
130 | false
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/60-documentation/initial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | documentation-initial
7 |
8 | 6 - Documentation - Initial
9 |
10 |
11 | de.odrotbohm.smdd
12 | documentation
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 | org.jmolecules
21 | jmolecules-bom
22 | ${jmolecules.version}
23 | pom
24 | import
25 |
26 |
27 | org.springframework.modulith
28 | spring-modulith-bom
29 | ${spring-modulith.version}
30 | pom
31 | import
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.jmolecules.integrations
40 | jmolecules-starter-ddd
41 |
42 |
43 |
44 | org.jmolecules.integrations
45 | jmolecules-spring
46 | runtime
47 |
48 |
49 |
50 | org.jmolecules.integrations
51 | jmolecules-jpa
52 | runtime
53 |
54 |
55 |
56 | org.jmolecules.integrations
57 | jmolecules-bytebuddy-nodep
58 |
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-starter-data-jpa
65 |
66 |
67 |
68 | org.springframework.boot
69 | spring-boot-starter-test
70 | test
71 |
72 |
73 |
74 |
75 |
76 | org.springframework.modulith
77 | spring-modulith-events-api
78 |
79 |
80 |
81 | org.springframework.modulith
82 | spring-modulith-core
83 | test
84 |
85 |
86 |
87 |
88 |
89 | org.projectlombok
90 | lombok
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | net.bytebuddy
100 | byte-buddy-maven-plugin
101 | ${bytebuddy.version}
102 |
103 | true
104 |
105 |
106 |
107 |
108 | transform-extended
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | docs
121 |
122 |
123 |
124 | org.asciidoctor
125 | asciidoctor-maven-plugin
126 | 3.0.0
127 |
128 |
129 | org.asciidoctor
130 | asciidoctorj-diagram
131 | 2.3.1
132 |
133 |
134 |
135 |
136 | asciidoc-to-html
137 | package
138 |
139 | process-asciidoc
140 |
141 |
142 |
143 | asciidoctor-diagram
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/60-documentation/complete/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | documentation-complete
7 |
8 | 6 - Documentation - Complete
9 |
10 |
11 | de.odrotbohm.smdd
12 | documentation
13 | 1.0-SNAPSHOT
14 | ../pom.xml
15 |
16 |
17 |
18 |
19 |
20 | org.jmolecules
21 | jmolecules-bom
22 | ${jmolecules.version}
23 | pom
24 | import
25 |
26 |
27 | org.springframework.modulith
28 | spring-modulith-bom
29 | ${spring-modulith.version}
30 | pom
31 | import
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.jmolecules.integrations
40 | jmolecules-starter-ddd
41 |
42 |
43 |
44 | org.jmolecules.integrations
45 | jmolecules-spring
46 | runtime
47 |
48 |
49 |
50 | org.jmolecules.integrations
51 | jmolecules-jpa
52 | runtime
53 |
54 |
55 |
56 | org.jmolecules.integrations
57 | jmolecules-bytebuddy-nodep
58 |
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-starter-data-jpa
65 |
66 |
67 |
68 |
69 |
70 | org.springframework.modulith
71 | spring-modulith-events-api
72 |
73 |
74 |
75 | org.springframework.modulith
76 | spring-modulith-starter-test
77 | test
78 |
79 |
80 |
81 |
82 |
83 | org.projectlombok
84 | lombok
85 |
86 |
87 |
88 | org.springframework.boot
89 | spring-boot-configuration-processor
90 | true
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | net.bytebuddy
100 | byte-buddy-maven-plugin
101 | ${bytebuddy.version}
102 |
103 | true
104 |
105 |
106 |
107 |
108 | transform-extended
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | docs
121 |
122 |
123 |
124 | org.asciidoctor
125 | asciidoctor-maven-plugin
126 | 3.0.0
127 |
128 |
129 | org.asciidoctor
130 | asciidoctorj-diagram
131 | 2.3.1
132 |
133 |
134 |
135 |
136 | asciidoc-to-html
137 | package
138 |
139 | process-asciidoc
140 |
141 |
142 |
143 | asciidoctor-diagram
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/10-fundamentals/102-creating-modules.adoc:
--------------------------------------------------------------------------------
1 | [[fundamentals.creating-modules]]
2 | = 🧑💻 Creating Application Modules
3 | :tabsize: 2
4 | :source: complete/src/main/java/com/example/app
5 | :test-source: complete/src/test/java/com/example/app
6 |
7 | [[fundamentals.creating-modules.objectives]]
8 | == 🎯 Objectives
9 |
10 | You'll learn how to…
11 |
12 | * … create an application module within the application.
13 | * … bootstrap `ApplicationModules`.
14 | * … inspect the application module model on the command line.
15 |
16 | [[fundamentals.creating-modules.preparations]]
17 | == 👣 Preparations
18 |
19 | . Create a test class in the application's root package in `src/test/java` named `ApplicationModularityTests`.
20 | +
21 | ifndef::educates[]
22 | [source, java]
23 | ----
24 | package com.example.app;
25 |
26 | class ApplicationModularityTests {
27 | }
28 | ----
29 | endif::[]
30 |
31 | . Within that class, create a test case to derive the application's module model.
32 | Create a new instance of `ApplicationModules` pointing to the root Spring Boot application class.
33 |
34 | . Print the result to the console.
35 | +
36 | ifndef::educates[]
37 | [source, java]
38 | ----
39 | @Test
40 | void bootstrapsApplicationModules() {
41 |
42 | var modules = ApplicationModules.of(Application.class);
43 |
44 | System.out.println(modules);
45 | }
46 | ----
47 | endif::[]
48 | +
49 | ifdef::educates[]
50 | Expand the section below for clickable instructions.
51 | +
52 | [source, section:begin]
53 | ----
54 | title: "Clickable instructions"
55 | ----
56 | +
57 | [source, terminal:execute-all]
58 | ----
59 | command: mkdir -p src/test/java/com/example/app
60 | autostart: true
61 | hidden: true
62 | ----
63 | +
64 | [source, dashboard:reload-dashboard]
65 | ----
66 | name: Editor
67 | autostart: true
68 | hidden: true
69 | ----
70 | +
71 | [source, editor:append-lines-to-file]
72 | ----
73 | file: ~/exercises/src/test/java/com/example/app/ApplicationModularityTests.java
74 | text: |
75 | package com.example.app;
76 |
77 | class ApplicationModularityTests {}
78 | ----
79 | +
80 | [source, editor:select-matching-text]
81 | ----
82 | file: ~/exercises/src/test/java/com/example/app/ApplicationModularityTests.java
83 | text: "class ApplicationModularityTests {"
84 | before: 0
85 | after: 1
86 | ----
87 | +
88 | [source, editor:replace-text-selection]
89 | ----
90 | file: ~/exercises/src/test/java/com/example/app/ApplicationModularityTests.java
91 | text: |
92 | import org.junit.jupiter.api.Test;
93 | import org.springframework.modulith.core.ApplicationModules;
94 |
95 | class ApplicationModularityTests {
96 |
97 | @Test
98 | void bootstrapsApplicationModules() {
99 |
100 | var modules = ApplicationModules.of(Application.class);
101 |
102 | System.out.println(modules);
103 | }
104 | }
105 | ----
106 | +
107 | [source, section:end]
108 | ----
109 | ----
110 | endif::[]
111 | +
112 | Execute the test and note, how the output does not list any Spring Modulith specific information.
113 | +
114 | ifdef::educates[]
115 | [source, terminal:execute]
116 | ----
117 | command: mvnw test
118 | ----
119 | +
120 | endif::[]
121 |
122 | [source, bash]
123 | ----
124 | [INFO] -------------------------------------------------------
125 | [INFO] T E S T S
126 | [INFO] -------------------------------------------------------
127 | [INFO] Running com.example.app.ApplicationModularityTests
128 | … [main] INFO com.tngtech.archunit.core.PluginLoader -- Detected Java version 21.0.1
129 | ----
130 |
131 | [[fundamentals.creating-modules.adding-a-module]]
132 | == 👣 Adding a Module
133 |
134 | . Create a package `order`
135 | . Add a public type `OrderManagement` in that package and annotate the type with Spring's `@Component` annotation.
136 | +
137 | ifdef::educates[]
138 | Expand the section below for clickable instructions.
139 | +
140 | [source, section:begin]
141 | ----
142 | title: "Clickable instructions"
143 | ----
144 | +
145 | [source, terminal:execute-all]
146 | ----
147 | command: mkdir -p src/main/java/com/example/app/order
148 | autostart: true
149 | hidden: true
150 | ----
151 | +
152 | [source, dashboard:reload-dashboard]
153 | ----
154 | name: Editor
155 | autostart: true
156 | hidden: true
157 | ----
158 | +
159 | [source, editor:append-lines-to-file]
160 | ----
161 | file: ~/exercises/src/main/java/com/example/app/order/OrderManagement.java
162 | text: |
163 | package com.example.app.order;
164 |
165 | import org.springframework.stereotype.Component;
166 |
167 | @Component
168 | public class OrderManagement {}
169 | ----
170 | +
171 | [source, section:end]
172 | ----
173 | ----
174 | endif::[]
175 |
176 | . Re-run the test case to see an application module named `Order` is listed, as well as `OrderManagement` as public component.
177 | +
178 | ifdef::educates[]
179 | [source, terminal:execute]
180 | ----
181 | command: mvnw test
182 | ----
183 | +
184 | endif::[]
185 |
186 | [source, bash]
187 | ----
188 | [INFO] -------------------------------------------------------
189 | [INFO] T E S T S
190 | [INFO] -------------------------------------------------------
191 | [INFO] Running com.example.app.ApplicationModularityTests
192 | … [main] INFO com.tngtech.archunit.core.PluginLoader -- Detected Java version 21.0.1
193 | # Order
194 | > Logical name: order
195 | > Base package: com.example.app.order
196 | > Direct module dependencies: none
197 | > Spring beans:
198 | + ….OrderManagement
199 | ----
200 |
201 | [[fundamentals.creating-modules.further-ideas]]
202 | == 💡 Further ideas
203 | * What happens if you add sibling packages to `order` containing Spring bean classes in them?
204 | * How does changing the visibility modifier of the types in the packages change the test output?
205 | * How does the test output change if you introduce a dependency between components in different modules?
206 |
207 | ifdef::educates[]
208 | [[fundamentals.creating-modules.help]]
209 | == 💡 Help!
210 |
211 | If you're having trouble with the code, expand this section for help.
212 |
213 | [source, section:begin]
214 | ----
215 | title: "Solution"
216 | ----
217 |
218 | [source, java]
219 | ----
220 | package com.example.app;
221 |
222 | import org.junit.jupiter.api.Test;
223 | import org.springframework.modulith.core.ApplicationModules;
224 |
225 | class ApplicationModularityTests {
226 |
227 | @Test
228 | void bootstrapsApplicationModules() {
229 |
230 | var modules = ApplicationModules.of(Application.class);
231 |
232 | System.out.println(modules);
233 | }
234 | }
235 | ----
236 |
237 | [source, java]
238 | ----
239 | package com.example.app.order;
240 |
241 | import org.springframework.stereotype.Component;
242 |
243 | @Component
244 | public class OrderManagement {}
245 | ----
246 |
247 | [source, section:end]
248 | ----
249 | ----
250 | endif::[]
251 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Apache Maven Wrapper startup batch script, version 3.1.1
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
30 | @REM e.g. to debug Maven itself, use
31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
33 | @REM ----------------------------------------------------------------------------
34 |
35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
36 | @echo off
37 | @REM set title of command window
38 | title %0
39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
40 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
41 |
42 | @REM set %HOME% to equivalent of $HOME
43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
44 |
45 | @REM Execute a user defined script before this one
46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
50 | :skipRcPre
51 |
52 | @setlocal
53 |
54 | set ERROR_CODE=0
55 |
56 | @REM To isolate internal variables from possible post scripts, we use another setlocal
57 | @setlocal
58 |
59 | @REM ==== START VALIDATION ====
60 | if not "%JAVA_HOME%" == "" goto OkJHome
61 |
62 | echo.
63 | echo Error: JAVA_HOME not found in your environment. >&2
64 | echo Please set the JAVA_HOME variable in your environment to match the >&2
65 | echo location of your Java installation. >&2
66 | echo.
67 | goto error
68 |
69 | :OkJHome
70 | if exist "%JAVA_HOME%\bin\java.exe" goto init
71 |
72 | echo.
73 | echo Error: JAVA_HOME is set to an invalid directory. >&2
74 | echo JAVA_HOME = "%JAVA_HOME%" >&2
75 | echo Please set the JAVA_HOME variable in your environment to match the >&2
76 | echo location of your Java installation. >&2
77 | echo.
78 | goto error
79 |
80 | @REM ==== END VALIDATION ====
81 |
82 | :init
83 |
84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
85 | @REM Fallback to current working directory if not found.
86 |
87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
89 |
90 | set EXEC_DIR=%CD%
91 | set WDIR=%EXEC_DIR%
92 | :findBaseDir
93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
94 | cd ..
95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
96 | set WDIR=%CD%
97 | goto findBaseDir
98 |
99 | :baseDirFound
100 | set MAVEN_PROJECTBASEDIR=%WDIR%
101 | cd "%EXEC_DIR%"
102 | goto endDetectBaseDir
103 |
104 | :baseDirNotFound
105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
106 | cd "%EXEC_DIR%"
107 |
108 | :endDetectBaseDir
109 |
110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
111 |
112 | @setlocal EnableExtensions EnableDelayedExpansion
113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
115 |
116 | :endReadAdditionalConfig
117 |
118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
123 |
124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
125 | IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
126 | )
127 |
128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130 | if exist %WRAPPER_JAR% (
131 | if "%MVNW_VERBOSE%" == "true" (
132 | echo Found %WRAPPER_JAR%
133 | )
134 | ) else (
135 | if not "%MVNW_REPOURL%" == "" (
136 | SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
137 | )
138 | if "%MVNW_VERBOSE%" == "true" (
139 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
140 | echo Downloading from: %WRAPPER_URL%
141 | )
142 |
143 | powershell -Command "&{"^
144 | "$webclient = new-object System.Net.WebClient;"^
145 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
146 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
147 | "}"^
148 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
149 | "}"
150 | if "%MVNW_VERBOSE%" == "true" (
151 | echo Finished downloading %WRAPPER_JAR%
152 | )
153 | )
154 | @REM End of extension
155 |
156 | @REM Provide a "standardized" way to retrieve the CLI args that will
157 | @REM work with both Windows and non-Windows executions.
158 | set MAVEN_CMD_LINE_ARGS=%*
159 |
160 | %MAVEN_JAVA_EXE% ^
161 | %JVM_CONFIG_MAVEN_PROPS% ^
162 | %MAVEN_OPTS% ^
163 | %MAVEN_DEBUG_OPTS% ^
164 | -classpath %WRAPPER_JAR% ^
165 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
166 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
167 | if ERRORLEVEL 1 goto error
168 | goto end
169 |
170 | :error
171 | set ERROR_CODE=1
172 |
173 | :end
174 | @endlocal & set ERROR_CODE=%ERROR_CODE%
175 |
176 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
177 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
178 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
179 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
180 | :skipRcPost
181 |
182 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
183 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
184 |
185 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
186 |
187 | cmd /C exit /B %ERROR_CODE%
188 |
--------------------------------------------------------------------------------