./mvnw install && ./mvnw spring-boot:run -pl delivery
or
./mvnw install && java -jar delivery/target/delivery-1.0.0-SNAPSHOT.jar
The project consists of 4 modules core
, usecases
, dataproviders
, and
delivery
.
This module contains the domain entities. There are no dependencies to frameworks and/or libraries.
This module contains the business rules that are essential for our application
(Application business rules). The only dependency of this module is to core
.
In this module, gateways for the repositories are being defined. Each use case
defines the interface of the gateway that is required following the
ISP. These
gateways, operate on the domain entities defined in core
.
In this module,
UseCase
and
UseCaseExecutor
are also defined. The UseCase
is an interface similar to the
java.util.Function
. It just gets a request and returns a response.
The UseCaseExecutor
handles the execution of a UseCase
. To do so, it has an
invoke
method that takes the following arguments:
- the use case that is to be executed
- the RequestDto
- a function that converts the RequestDto to a Request object (the input of the use case)
- a function that converts the Response object (the output of the use case) of the use case execution to a ResponseDto
There are 3 more overloaded versions of the invoke
method, which omit the input
and/or the output of the UseCaseExecutor
.
Currently, the UseCaseExecutor
implementation
(UseCaseExecutorImp
)
is using java.util.concurrent.CompletableFuture
and
java.util.concurrent.CompletionStage
for the execution abstraction. These
abstractions are convenient as they can perform asynchronous executions and also
have out of the box compatibility with most frameworks.
This module contains the implementation of the gateways defined in the
usecases
module. This module depends on the framework that facilitates the
data access. In our example, we use JPA and Spring Data. The Jpa*Repository
classes are the actual implementation of the gateways defined in the usecases
module.
These repositories, use the Spring Data JpaRepository
as dependencies.
For more, check
JpaProductRepository.kt.
The entities in this module, are JPA entities, so mappings to and from these and
the domain entities are needed. Check
ProductEntity.kt
for more.
This module contains all the details of the delivery mechanism that we use along
with the wiring of the app and the configurations. In our example, we use rest services
built with Spring Boot. Similarly, to the JPA entities of the
dataproviders
module, the DTOs have mappers, to convert from and to the domain
entities.
A rest controller gets the RequestDto, and forwards it to the related
use case through the UseCaseExecutor
. The response of the use case (which is a ResponseDto) is the response of the
controller's method that implements the endpoint. An example of such usage is
ProductResourceImp.kt.
The exceptions are handled by
GlobalExceptionHandler.kt,
and they are converted to
ErrorDto.