Files

50 lines
4.5 KiB
Plaintext

$ mvn -pl order-fulfillment -am test -Dtest=ModularityTests#verifiesModuleStructure
(captured with OrderManagement holding a direct field of type
com.ankurm.modulithdemo.inventory.internal.StockRepository)
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.768 s <<< FAILURE! -- in com.ankurm.modulithdemo.ModularityTests
[ERROR] com.ankurm.modulithdemo.ModularityTests.verifiesModuleStructure -- Time elapsed: 0.120 s <<< ERROR!
org.springframework.modulith.core.Violations:
- Cycle detected: Slice inventory ->
Slice order ->
Slice inventory
1. Dependencies of Slice inventory
- Method <com.ankurm.modulithdemo.inventory.InventoryManagement.on(com.ankurm.modulithdemo.order.OrderPlaced)> has parameter of type <com.ankurm.modulithdemo.order.OrderPlaced> in (InventoryManagement.java:0)
- Method <com.ankurm.modulithdemo.inventory.InventoryManagement.on(com.ankurm.modulithdemo.order.OrderPlaced)> calls method <com.ankurm.modulithdemo.order.OrderPlaced.sku()> in (InventoryManagement.java:44)
- Method <com.ankurm.modulithdemo.inventory.InventoryManagement.on(com.ankurm.modulithdemo.order.OrderPlaced)> calls method <com.ankurm.modulithdemo.order.OrderPlaced.quantity()> in (InventoryManagement.java:45)
- Method <com.ankurm.modulithdemo.inventory.InventoryManagement.on(com.ankurm.modulithdemo.order.OrderPlaced)> calls method <com.ankurm.modulithdemo.order.OrderPlaced.orderId()> in (InventoryManagement.java:48)
2. Dependencies of Slice order
- Constructor <com.ankurm.modulithdemo.order.OrderManagement.<init>(..., StockRepository)> has parameter of type <com.ankurm.modulithdemo.inventory.internal.StockRepository> in (OrderManagement.java:0)
- Field <com.ankurm.modulithdemo.order.OrderManagement.stockShortcut> has type <com.ankurm.modulithdemo.inventory.internal.StockRepository> in (OrderManagement.java:0)
- Method <com.ankurm.modulithdemo.order.OrderManagement.placeOrder(java.lang.String, int)> calls method <com.ankurm.modulithdemo.inventory.internal.StockRepository.findBySku(java.lang.String)> in (OrderManagement.java:39)
- Module 'order' depends on non-exposed type com.ankurm.modulithdemo.inventory.internal.StockRepository within module 'inventory'!
OrderManagement declares constructor OrderManagement(OrderRepository, ApplicationEventPublisher, StockRepository) in (OrderManagement.java:0)
- Module 'order' depends on non-exposed type com.ankurm.modulithdemo.inventory.internal.StockRepository within module 'inventory'!
Method <com.ankurm.modulithdemo.order.OrderManagement.placeOrder(java.lang.String, int)> calls method <com.ankurm.modulithdemo.inventory.internal.StockRepository.findBySku(java.lang.String)> in (OrderManagement.java:39)
- Module 'order' depends on non-exposed type com.ankurm.modulithdemo.inventory.internal.StockRepository within module 'inventory'!
Field <com.ankurm.modulithdemo.order.OrderManagement.stockShortcut> has type <com.ankurm.modulithdemo.inventory.internal.StockRepository> in (OrderManagement.java:0)
at org.springframework.modulith.core.Violations.and(Violations.java:141)
at org.springframework.modulith.core.ApplicationModules.detectViolations(ApplicationModules.java:497)
at org.springframework.modulith.core.ApplicationModules.verify(ApplicationModules.java:451)
at org.springframework.modulith.core.ApplicationModules.verify(ApplicationModules.java:435)
at com.ankurm.modulithdemo.ModularityTests.verifiesModuleStructure(ModularityTests.java:28)
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
One field in OrderManagement produced TWO distinct violation types in the same run:
1. "Cycle detected" - inventory already depends on order (it listens for OrderPlaced,
so it necessarily knows about order's event type). Order reaching back into
inventory's internals closes a cycle: order -> inventory -> order. Spring Modulith
treats module dependencies as a DAG by default; a cycle is a structural violation
even before asking whether the specific type reached for was internal.
2. "depends on non-exposed type" - independent of the cycle, StockRepository lives
under inventory.internal, which nothing outside the inventory package is allowed
to reference, exposed or not.
Either violation alone would have failed the build. This one shortcut produced both at
once, which is the realistic case: an internal type reached across a boundary usually
also reverses or closes a dependency cycle, because the "proper" event-based direction
was already established the other way.