Skip to content

Commit 5232372

Browse files
committed
GH-156 - Polish example.
Add sample documentation. Reintroduce Lombok to avoid boilerplate. Use jMolecules DDD abstractions to represent aggregates. Use Scenario API in test cases.
1 parent 45d51dd commit 5232372

File tree

10 files changed

+80
-59
lines changed

10 files changed

+80
-59
lines changed

spring-modulith-example/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272

7373
<!-- jMolecules -->
7474

75+
<dependency>
76+
<groupId>org.jmolecules</groupId>
77+
<artifactId>jmolecules-ddd</artifactId>
78+
</dependency>
79+
7580
<dependency>
7681
<groupId>org.jmolecules</groupId>
7782
<artifactId>jmolecules-events</artifactId>
@@ -112,6 +117,12 @@
112117
<optional>true</optional>
113118
</dependency>
114119

120+
<dependency>
121+
<groupId>org.projectlombok</groupId>
122+
<artifactId>lombok</artifactId>
123+
<scope>provided</scope>
124+
</dependency>
125+
115126
</dependencies>
116127

117128
<repositories>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
= Spring Modulith Example Documentation
2+
:modulith-docs: ../../../target/spring-modulith-docs
3+
4+
== Overview
5+
6+
plantuml::{modulith-docs}/components.puml[format="svg"]
7+
8+
== Inventory
9+
10+
plantuml::{modulith-docs}/module-inventory.puml[format="svg"]
11+
include::{modulith-docs}/module-inventory.adoc[]
12+
13+
== Orders
14+
15+
plantuml::{modulith-docs}/module-order.puml[format="svg"]
16+
include::{modulith-docs}/module-order.adoc[]

spring-modulith-example/src/main/java/example/inventory/InventoryManagement.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package example.inventory;
1717

1818
import example.order.OrderCompleted;
19+
import lombok.RequiredArgsConstructor;
1920

2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
@@ -28,15 +29,12 @@
2829
* @author Oliver Drotbohm
2930
*/
3031
@Service
31-
public class InventoryManagement {
32+
@RequiredArgsConstructor
33+
class InventoryManagement {
3234

3335
private static final Logger LOG = LoggerFactory.getLogger(InventoryManagement.class);
3436

35-
final InventoryInternal dependency;
36-
37-
InventoryManagement(InventoryInternal dependency) {
38-
this.dependency = dependency;
39-
}
37+
private final InventoryInternal dependency;
4038

4139
@ApplicationModuleListener
4240
void on(OrderCompleted event) throws InterruptedException {

spring-modulith-example/src/main/java/example/inventory/package-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
*
55
* @see example.inventory.InventoryInternal
66
*/
7+
@org.springframework.lang.NonNullApi
78
package example.inventory;

spring-modulith-example/src/main/java/example/order/Order.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,20 @@
1515
*/
1616
package example.order;
1717

18+
import example.order.Order.OrderIdentifier;
19+
import lombok.Getter;
20+
1821
import java.util.UUID;
1922

23+
import org.jmolecules.ddd.types.AggregateRoot;
24+
import org.jmolecules.ddd.types.Identifier;
25+
2026
/**
2127
* @author Oliver Drotbohm
2228
*/
23-
public class Order {
24-
25-
private OrderIdentifier id = new OrderIdentifier(UUID.randomUUID());
29+
public class Order implements AggregateRoot<Order, OrderIdentifier> {
2630

27-
public OrderIdentifier getId() {
28-
return id;
29-
}
31+
private @Getter OrderIdentifier id = new OrderIdentifier(UUID.randomUUID());
3032

31-
public static record OrderIdentifier(UUID id) {}
33+
public static record OrderIdentifier(UUID id) implements Identifier {}
3234
}

spring-modulith-example/src/main/java/example/order/OrderManagement.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package example.order;
1717

1818
import example.order.internal.OrderInternal;
19+
import lombok.NonNull;
20+
import lombok.RequiredArgsConstructor;
1921

2022
import org.springframework.context.ApplicationEventPublisher;
2123
import org.springframework.stereotype.Service;
@@ -25,16 +27,11 @@
2527
* @author Oliver Drotbohm
2628
*/
2729
@Service
30+
@RequiredArgsConstructor
2831
public class OrderManagement {
2932

30-
final ApplicationEventPublisher events;
31-
final OrderInternal dependency;
32-
33-
OrderManagement(ApplicationEventPublisher events, OrderInternal dependency) {
34-
35-
this.events = events;
36-
this.dependency = dependency;
37-
}
33+
private final @NonNull ApplicationEventPublisher events;
34+
private final @NonNull OrderInternal dependency;
3835

3936
@Transactional
4037
public void complete(Order order) {

spring-modulith-example/src/main/java/example/order/internal/OrderInternal.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
import org.springframework.stereotype.Component;
1919

2020
/**
21-
* Some order-internal application component.
21+
* Some order-internal application component. Referring to it from the inventory module would be captured by
22+
* {@link example.ModularityTests}.
2223
*
2324
* @author Oliver Drotbohm
2425
*/

spring-modulith-example/src/main/java/example/order/package-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
*
55
* @see example.ModularityTests
66
*/
7+
@org.springframework.lang.NonNullApi
78
package example.order;

spring-modulith-example/src/test/java/example/order/EventPublicationRegistryTests.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
import static org.assertj.core.api.Assertions.*;
1919

2020
import example.order.EventPublicationRegistryTests.FailingAsyncTransactionalEventListener;
21+
import lombok.Getter;
22+
import lombok.RequiredArgsConstructor;
2123

2224
import org.junit.jupiter.api.Test;
2325
import org.springframework.context.annotation.Import;
2426
import org.springframework.modulith.ApplicationModuleListener;
2527
import org.springframework.modulith.events.EventPublicationRegistry;
2628
import org.springframework.modulith.test.ApplicationModuleTest;
29+
import org.springframework.modulith.test.Scenario;
2730
import org.springframework.test.annotation.DirtiesContext;
2831

2932
/**
@@ -35,37 +38,41 @@
3538
@ApplicationModuleTest
3639
@Import(FailingAsyncTransactionalEventListener.class)
3740
@DirtiesContext
41+
@RequiredArgsConstructor
3842
class EventPublicationRegistryTests {
3943

4044
private final OrderManagement orders;
4145
private final EventPublicationRegistry registry;
42-
43-
/**
44-
* @param orders
45-
* @param registry
46-
*/
47-
EventPublicationRegistryTests(OrderManagement orders, EventPublicationRegistry registry) {
48-
this.orders = orders;
49-
this.registry = registry;
50-
}
46+
private final FailingAsyncTransactionalEventListener listener;
5147

5248
@Test
53-
void leavesPublicationIncompleteForFailingListener() throws Exception {
49+
void leavesPublicationIncompleteForFailingListener(Scenario scenario) throws Exception {
5450

5551
var order = new Order();
5652

57-
orders.complete(order);
58-
59-
Thread.sleep(40);
60-
61-
assertThat(registry.findIncompletePublications()).hasSize(1);
53+
scenario.stimulate(() -> orders.complete(order))
54+
.andWaitForStateChange(() -> listener.getEx())
55+
.andVerify(__ -> {
56+
assertThat(registry.findIncompletePublications()).hasSize(1);
57+
});
6258
}
6359

6460
static class FailingAsyncTransactionalEventListener {
6561

62+
@Getter Exception ex;
63+
6664
@ApplicationModuleListener
6765
void foo(OrderCompleted event) {
68-
throw new IllegalStateException();
66+
67+
var exception = new IllegalStateException(\\_(ツ)_/¯");
68+
69+
try {
70+
71+
throw exception;
72+
73+
} finally {
74+
this.ex = exception;
75+
}
6976
}
7077
}
7178
}

spring-modulith-example/src/test/java/example/order/OrderIntegrationTests.java

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,29 @@
1515
*/
1616
package example.order;
1717

18-
import static org.assertj.core.api.Assertions.*;
18+
import lombok.RequiredArgsConstructor;
1919

2020
import org.junit.jupiter.api.Test;
2121
import org.springframework.modulith.test.ApplicationModuleTest;
22-
import org.springframework.modulith.test.AssertablePublishedEvents;
22+
import org.springframework.modulith.test.Scenario;
2323

2424
/**
2525
* @author Oliver Drotbohm
2626
*/
2727
@ApplicationModuleTest
28+
@RequiredArgsConstructor
2829
class OrderIntegrationTests {
2930

3031
private final OrderManagement orders;
3132

32-
OrderIntegrationTests(OrderManagement orders) {
33-
this.orders = orders;
34-
}
35-
3633
@Test
37-
void publishesOrderCompletion(AssertablePublishedEvents events) {
34+
void publishesOrderCompletion(Scenario scenario) {
3835

3936
var reference = new Order();
4037

41-
orders.complete(reference);
42-
43-
// Verification
44-
45-
var matchingMapped = events.ofType(OrderCompleted.class)
46-
.matching(OrderCompleted::orderId, reference.getId());
47-
48-
assertThat(matchingMapped).hasSize(1);
49-
50-
// AssertJ
51-
52-
assertThat(events)
53-
.contains(OrderCompleted.class)
54-
.matching(OrderCompleted::orderId, reference.getId());
38+
scenario.stimulate(() -> orders.complete(reference))
39+
.andWaitForEventOfType(OrderCompleted.class)
40+
.matchingMappedValue(OrderCompleted::orderId, reference.getId())
41+
.toArrive();
5542
}
5643
}

0 commit comments

Comments
 (0)