-
Notifications
You must be signed in to change notification settings - Fork 289
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
extend Onion Architecture to allow defining components by predicate
Some users use different conventions, like class naming or annotations, to define the components of their Onion Architecture. To support such use cases we extend `OnionArchitecture` similar to `LayeredArchitecture` to also allow defining components via any arbitrary `DescribedPredicate`. While extending the example I noticed that it might be a good addition to have a more generic `JavaClass.Predicates.belongTo(DescribedPredicate)` method additionally to `belongToAnyOf(Class<?>...)`. At least writing the example would otherwise have been tedious, since assigning nested and anonymous classes to the annotation of the outer class would always be necessary for this use case. Signed-off-by: Peter Gafert <peter.gafert@tngtech.com>
- Loading branch information
1 parent
163b59b
commit 6046075
Showing
30 changed files
with
754 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
...va/com/tngtech/archunit/example/onionarchitecture_by_annotations/annotations/Adapter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations; | ||
|
||
public @interface Adapter { | ||
String value(); | ||
} |
4 changes: 4 additions & 0 deletions
4
...om/tngtech/archunit/example/onionarchitecture_by_annotations/annotations/Application.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations; | ||
|
||
public @interface Application { | ||
} |
4 changes: 4 additions & 0 deletions
4
...om/tngtech/archunit/example/onionarchitecture_by_annotations/annotations/DomainModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations; | ||
|
||
public @interface DomainModel { | ||
} |
4 changes: 4 additions & 0 deletions
4
.../tngtech/archunit/example/onionarchitecture_by_annotations/annotations/DomainService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations; | ||
|
||
public @interface DomainService { | ||
} |
8 changes: 8 additions & 0 deletions
8
...m/tngtech/archunit/example/onionarchitecture_by_annotations/onion/AdministrationPort.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Application; | ||
|
||
@Application | ||
public interface AdministrationPort { | ||
<T> T getInstanceOf(Class<T> type); | ||
} |
19 changes: 19 additions & 0 deletions
19
.../tngtech/archunit/example/onionarchitecture_by_annotations/onion/ShoppingApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Application; | ||
|
||
@Application | ||
public class ShoppingApplication { | ||
public static void main(String[] args) { | ||
// start the whole application / provide IOC features | ||
} | ||
|
||
public static AdministrationPort openAdministrationPort() { | ||
return new AdministrationPort() { | ||
@Override | ||
public <T> T getInstanceOf(Class<T> type) { | ||
throw new UnsupportedOperationException("Not yet implemented"); | ||
} | ||
}; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...unit/example/onionarchitecture_by_annotations/onion/administration/AdministrationCLI.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.administration; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Adapter; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.AdministrationPort; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.ShoppingApplication; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product.ProductRepository; | ||
|
||
@Adapter("cli") | ||
@SuppressWarnings("unused") | ||
public class AdministrationCLI { | ||
public static void main(String[] args) { | ||
AdministrationPort port = ShoppingApplication.openAdministrationPort(); | ||
handle(args, port); | ||
} | ||
|
||
private static void handle(String[] args, AdministrationPort port) { | ||
// violates the pairwise independence of adapters | ||
ProductRepository repository = port.getInstanceOf(ProductRepository.class); | ||
long count = repository.getTotalCount(); | ||
// parse arguments and re-configure application according to count through port | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
.../com/tngtech/archunit/example/onionarchitecture_by_annotations/onion/order/OrderItem.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.order; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainModel; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product.Product; | ||
|
||
@DomainModel | ||
public class OrderItem { | ||
private final Product product; | ||
private final OrderQuantity quantity; | ||
|
||
public OrderItem(Product product, OrderQuantity quantity) { | ||
if (product == null) { | ||
throw new IllegalArgumentException("Product must not be null"); | ||
} | ||
if (quantity == null) { | ||
throw new IllegalArgumentException("Quantity not be null"); | ||
} | ||
this.product = product; | ||
this.quantity = quantity; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{product=" + product + ", quantity=" + quantity + '}'; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
.../tngtech/archunit/example/onionarchitecture_by_annotations/onion/order/OrderQuantity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.order; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainService; | ||
|
||
@DomainService | ||
@SuppressWarnings("unused") | ||
public class OrderQuantity { | ||
private final int quantity; | ||
|
||
public OrderQuantity(int quantity) { | ||
if (quantity <= 0) { | ||
throw new IllegalArgumentException("Quantity must be positive"); | ||
} | ||
this.quantity = quantity; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{quantity=" + quantity + '}'; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
.../tngtech/archunit/example/onionarchitecture_by_annotations/onion/order/PaymentMethod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.order; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainModel; | ||
|
||
@DomainModel | ||
public class PaymentMethod { | ||
} |
27 changes: 27 additions & 0 deletions
27
.../com/tngtech/archunit/example/onionarchitecture_by_annotations/onion/product/Product.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainModel; | ||
|
||
@DomainModel | ||
public class Product { | ||
// Dependency on ProductId violates the architecture, since ProductId resides with persistence adapter | ||
private final ProductId id; | ||
// Dependency on ProductName violates the architecture, since ProductName is located in the DomainService layer | ||
private final ProductName name; | ||
|
||
public Product(ProductId id, ProductName name) { | ||
if (id == null) { | ||
throw new IllegalArgumentException("Product id must not be null"); | ||
} | ||
if (name == null) { | ||
throw new IllegalArgumentException("Product name must not be null"); | ||
} | ||
this.id = id; | ||
this.name = name; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{id=" + id + ", name=" + name + '}'; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...om/tngtech/archunit/example/onionarchitecture_by_annotations/onion/product/ProductId.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product; | ||
|
||
import java.util.UUID; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Adapter; | ||
|
||
@Adapter("persistence") | ||
@SuppressWarnings("unused") | ||
public class ProductId { | ||
private final UUID id; | ||
|
||
public ProductId(UUID id) { | ||
if (id == null) { | ||
throw new IllegalArgumentException("ID must not be null"); | ||
} | ||
this.id = id; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{id=" + id + '}'; | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...archunit/example/onionarchitecture_by_annotations/onion/product/ProductJpaRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Adapter; | ||
|
||
@Adapter("persistence") | ||
@SuppressWarnings("unused") | ||
public class ProductJpaRepository implements ProductRepository { | ||
@Override | ||
public Product read(ProductId id) { | ||
return new Product(id, new ProductName("would normally be read")); | ||
} | ||
|
||
@Override | ||
public long getTotalCount() { | ||
return 0; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
.../tngtech/archunit/example/onionarchitecture_by_annotations/onion/product/ProductName.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainService; | ||
|
||
@DomainService | ||
@SuppressWarnings("unused") | ||
public class ProductName { | ||
private final String name; | ||
|
||
public ProductName(String name) { | ||
if (name == null || name.isEmpty()) { | ||
throw new IllegalArgumentException("Name must not be empty"); | ||
} | ||
this.name = name; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{name='" + name + '\'' + '}'; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...ch/archunit/example/onionarchitecture_by_annotations/onion/product/ProductRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.product; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.Adapter; | ||
|
||
// Violates the architecture because Domain must be the owner of the interfaces, not the persistence adapter | ||
@Adapter("persistence") | ||
public interface ProductRepository { | ||
Product read(ProductId id); | ||
|
||
long getTotalCount(); | ||
} |
32 changes: 32 additions & 0 deletions
32
...ngtech/archunit/example/onionarchitecture_by_annotations/onion/shopping/ShoppingCart.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.shopping; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.annotations.DomainModel; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.order.OrderItem; | ||
import com.tngtech.archunit.example.onionarchitecture_by_annotations.onion.order.PaymentMethod; | ||
|
||
@DomainModel | ||
@SuppressWarnings("unused") | ||
public class ShoppingCart { | ||
private final ShoppingCartId id; | ||
private final Set<OrderItem> orderItems = new HashSet<>(); | ||
|
||
public ShoppingCart(ShoppingCartId id) { | ||
this.id = id; | ||
} | ||
|
||
public void add(OrderItem orderItem) { | ||
orderItems.add(orderItem); | ||
} | ||
|
||
public void executeOrder(PaymentMethod method) { | ||
// complete financial transaction and initiate shipping process | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "{id=" + id + ", orderItems=" + orderItems + '}'; | ||
} | ||
} |
Oops, something went wrong.