Skip to content

Commit

Permalink
Refactor, adjust documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Mate Karolyi committed Jul 7, 2023
1 parent 92b3c76 commit b0791bc
Show file tree
Hide file tree
Showing 17 changed files with 165 additions and 143 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ An example of a Spring-Boot application, which based on the port and adapters/he

## Implementing new adapter

The key concept is that the component scan for the adapter package is excluded in the application, so the unnecessary adapter beans won't be loaded into the application context, just the configured ones.
The whole component scan for the adapter package is excluded in the application, so the unnecessary adapter beans won't be loaded into the application context, just the configured ones.
Each adapter defines her own spring configuration class, which is imported via the **@Import** annotation (on top of the application's main class) but getting only component scanned if the condition fulfills for it via **@ConditionalOnProperty** annotation.

Based on the below example if you define "spring-data-jpa" value as a persistence adapter in the application-[profile].yml,
then it will activate the corresponding Configuration class, which is going to component scan the underlying packages for spring beans.

### Example

Expand All @@ -45,9 +47,30 @@ adapter:
web: rest
```
## Build and test with Maven
```
mvn clean verify
```

**Building and verifying the application requires a running docker, since some tests are using
Testcontainers library!


### Test catalog and Maven lifecycle bindings

| Test catalog type | Maven lifecycle |
|:-----------------:|:---------------:|
| Unit test | test |
| Component test | test |
| ArchUnit test | test |
| Integration test | verify |
| Functional test | verify |

## API Documentation
You can access the API documentation locally at the following URL:

[http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html)

You can access the live API documentation at http://localhost:8080/swagger-ui/index.html

![Preview](img/openapi-swagger-ui.PNG)

Expand Down
13 changes: 12 additions & 1 deletion app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
<testcontainers.version>1.17.6</testcontainers.version>
<postgresql.version>42.5.4</postgresql.version>
<springdoc-openapi-starter-webmvc-ui.version>2.1.0</springdoc-openapi-starter-webmvc-ui.version>
<junit-jupiter.version>1.18.3</junit-jupiter.version>
<spring-boot-maven-plugin.mainClass>hu.hirannor.hexagonal.HexagonalApplication
</spring-boot-maven-plugin.mainClass>
</properties>

<dependencies>
Expand Down Expand Up @@ -98,6 +101,14 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>


<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
Expand All @@ -121,7 +132,7 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>hu.hirannor.hexagonal.HexagonalApplication</mainClass>
<mainClass>${spring-boot-maven-plugin.mainClass}</mainClass>
</configuration>
<executions>
<execution>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ class CustomerJpaRepository implements CustomerRepository {
public Customer updateDetails(final Customer domain) {
if (domain == null) throw new IllegalArgumentException(ERR_CUSTOMER_IS_NULL);

LOGGER.debug("Changing customer details for customer value: {}", domain.customerId());
LOGGER.debug("Changing customer details for customer id: {}", domain.customerId());

final CustomerModel model = customers.findByCustomerId(domain.customerId().asText())
.orElseThrow(
() -> new CustomerNotFound("Customer not found with value: " + domain)
() -> new CustomerNotFound("Customer not found with id: " + domain)
);

final CustomerModel modifiedCustomer = CustomerModeller.applyChangesFrom(domain).to(model);
Expand All @@ -86,7 +86,7 @@ public Customer updateDetails(final Customer domain) {
public void deleteBy(final CustomerId id) {
if (id == null) throw new IllegalArgumentException(ERR_CUSTOMER_ID_IS_NULL);

LOGGER.debug("Attempting to delete customer by value: {}", id);
LOGGER.debug("Attempting to delete customer by id: {}", id);

customers.deleteByCustomerId(id.asText());
}
Expand All @@ -111,7 +111,7 @@ public List<Customer> findAllBy(final FilterCriteria criteria) {
public Optional<Customer> findBy(final CustomerId id) {
if (id == null) throw new IllegalArgumentException(ERR_CUSTOMER_ID_IS_NULL);

LOGGER.debug("Fetching customer by value: {}", id);
LOGGER.debug("Fetching customer by id: {}", id);

return customers.findByCustomerId(id.value())
.map(mapModelToDomain);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import hu.hirannor.hexagonal.domain.customer.query.FilterCriteria;
import hu.hirannor.hexagonal.infrastructure.adapter.DriverAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

import java.net.URI;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
Expand All @@ -28,11 +28,8 @@
@DriverAdapter
class CustomerManagementController implements CustomersApi {

private static final String BASE_PATH = "/customers/";

private final Function<Customer, CustomerModel> mapCustomerToModel;
private final Function<RegisterCustomerModel, RegisterCustomer> mapRegisterCustomerToModel;
private final Function<AddressModel, Address> mapAddressModelToDomain;
private final Function<GenderModel, Gender> mapGenderModelToDomain;

private final CustomerDisplay customers;
Expand All @@ -52,7 +49,6 @@ class CustomerManagementController implements CustomersApi {
deletion,
CustomerMappingFactory.createCustomerToModelMapper(),
CustomerMappingFactory.createRegisterCustomerModelToDomainMapper(),
CustomerMappingFactory.createAddressModelToAddressMapper(),
CustomerMappingFactory.createGenderModelToDomainMapper()
);
}
Expand All @@ -63,24 +59,24 @@ class CustomerManagementController implements CustomersApi {
final CustomerDeletion deletion,
final Function<Customer, CustomerModel> mapCustomerToModel,
final Function<RegisterCustomerModel, RegisterCustomer> mapRegisterCustomerToModel,
final Function<AddressModel, Address> mapAddressModelToDomain,
final Function<GenderModel, Gender> mapGenderModelToDomain) {
this.customers = customers;
this.details = details;
this.deletion = deletion;
this.enrolling = enrolling;
this.mapCustomerToModel = mapCustomerToModel;
this.mapRegisterCustomerToModel = mapRegisterCustomerToModel;
this.mapAddressModelToDomain = mapAddressModelToDomain;
this.mapGenderModelToDomain = mapGenderModelToDomain;
}

@Override
public ResponseEntity<CustomerModel> changeDetails(final String customerId,
final ChangeCustomerDetailsModel model) {
final ChangeCustomerDetails cmd = assembleCommand(customerId, model);
final ChangeCustomerDetails cmd = CustomerMappingFactory
.createChangeCustomerDetailsModelToDomainMapper(customerId)
.apply(model);

final Customer changedCustomer = details.changeDetailsBy(cmd);
final Customer changedCustomer = details.changeBy(cmd);
final CustomerModel response = mapCustomerToModel.apply(changedCustomer);

return ResponseEntity.ok(response);
Expand Down Expand Up @@ -127,20 +123,7 @@ public ResponseEntity<CustomerModel> register(final RegisterCustomerModel model)
final RegisterCustomer cmd = mapRegisterCustomerToModel.apply(model);
final Customer registeredCustomer = enrolling.register(cmd);

return ResponseEntity.created(
URI.create(BASE_PATH + registeredCustomer.customerId().asText())
).body(mapCustomerToModel.apply(registeredCustomer));
return new ResponseEntity<>(mapCustomerToModel.apply(registeredCustomer), HttpStatus.CREATED);
}

private ChangeCustomerDetails assembleCommand(final String customerId,
final ChangeCustomerDetailsModel model) {
return new ChangeCustomerDetails.Builder()
.customerId(CustomerId.from(customerId))
.fullName(FullName.from(model.getFirstName(), model.getLastName()))
.gender(mapGenderModelToDomain.apply(model.getGender()))
.birthDate(model.getBirthDate())
.address(mapAddressModelToDomain.apply(model.getAddress()))
.email(EmailAddress.from(model.getEmailAddress()))
.assemble();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package hu.hirannor.hexagonal.adapter.web.rest.customer.mapping;

import hu.hirannor.hexagonal.adapter.web.rest.customer.model.*;
import hu.hirannor.hexagonal.domain.customer.*;
import hu.hirannor.hexagonal.domain.customer.command.ChangeCustomerDetails;

import java.util.function.Function;

/**
* Maps a {@link ChangeCustomerDetailsModel} model type to {@link ChangeCustomerDetails} domain type.
*
* @author Mate Karolyi
*/
class ChangeCustomerDetailsModelToDomainMapper implements Function<ChangeCustomerDetailsModel, ChangeCustomerDetails> {

private final String customerId;

private final Function<GenderModel, Gender> mapGenderModelToDomain;
private final Function<AddressModel, Address> mapAddressModelToDomain;

ChangeCustomerDetailsModelToDomainMapper(final String customerId) {
this(
customerId,
CustomerMappingFactory.createGenderModelToDomainMapper(),
CustomerMappingFactory.createAddressModelToAddressMapper()
);
}

ChangeCustomerDetailsModelToDomainMapper(final String customerId,
final Function<GenderModel, Gender> mapGenderModelToDomain,
final Function<AddressModel, Address> mapAddressModelToDomain) {
this.customerId = customerId;
this.mapGenderModelToDomain = mapGenderModelToDomain;
this.mapAddressModelToDomain = mapAddressModelToDomain;
}


@Override
public ChangeCustomerDetails apply(final ChangeCustomerDetailsModel model) {
return new ChangeCustomerDetails.Builder()
.customerId(CustomerId.from(customerId))
.fullName(FullName.from(model.getFirstName(), model.getLastName()))
.gender(mapGenderModelToDomain.apply(model.getGender()))
.birthDate(model.getBirthDate())
.address(mapAddressModelToDomain.apply(model.getAddress()))
.email(EmailAddress.from(model.getEmailAddress()))
.assemble();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import hu.hirannor.hexagonal.adapter.web.rest.customer.model.*;
import hu.hirannor.hexagonal.domain.customer.*;
import hu.hirannor.hexagonal.domain.customer.command.ChangeCustomerDetails;
import hu.hirannor.hexagonal.domain.customer.command.RegisterCustomer;

import java.util.function.Function;
Expand Down Expand Up @@ -53,4 +54,16 @@ static Function<AddressModel, Address> createAddressModelToAddressMapper() {
return new AddressModelToDomainMapper();
}

/**
* Create an instance of {@link ChangeCustomerDetailsModelToDomainMapper},
* which maps a {@link ChangeCustomerDetailsModel} model type
* to a {@link ChangeCustomerDetails} domain type.
*
* @return an instance of {@link ChangeCustomerDetailsModelToDomainMapper}
*/
static Function<ChangeCustomerDetailsModel, ChangeCustomerDetails> createChangeCustomerDetailsModelToDomainMapper(
final String customerId) {
return new ChangeCustomerDetailsModelToDomainMapper(customerId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CustomerManagementService implements
}

@Override
public Customer changeDetailsBy(final ChangeCustomerDetails cmd) {
public Customer changeBy(final ChangeCustomerDetails cmd) {
if (cmd == null) throw new IllegalArgumentException("ChangeCustomerDetails command cannot be null!");

final Customer foundCustomer = customers.findBy(cmd.customerId())
Expand All @@ -64,7 +64,7 @@ public Customer changeDetailsBy(final ChangeCustomerDetails cmd) {
messages.publish(updatedCustomer.listEvents());
updatedCustomer.clearEvents();

LOGGER.info("Customer details for customer value: {} are updated successfully!", updatedCustomer.customerId());
LOGGER.info("Customer details for customer id: {} are updated successfully!", updatedCustomer.customerId());

return updatedCustomer;
}
Expand All @@ -78,7 +78,7 @@ public void deleteBy(final CustomerId customerId) {
() -> new CustomerNotFound(String.format(ERR_CUSTOMER_NOT_FOUND, customerId.asText()))
);

LOGGER.info("Attempting to delete customer by value: {}", customerId.asText());
LOGGER.info("Attempting to delete customer by id: {}", customerId.asText());

customers.deleteBy(customerId);
}
Expand All @@ -96,7 +96,7 @@ public List<Customer> displayAllBy(final FilterCriteria criteria) {
public Optional<Customer> displayBy(final CustomerId customerId) {
if (customerId == null) throw new IllegalArgumentException(ERR_CUSTOMER_ID_IS_NULL);

LOGGER.info("Retrieving customer by value: {}", customerId);
LOGGER.info("Retrieving customer by id: {}", customerId);

return customers.findBy(customerId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ public interface CustomerModification {
* @param cmd {@link ChangeCustomerDetails} including the modifications
* @return {@link Customer} customer with modified details
*/
Customer changeDetailsBy(ChangeCustomerDetails cmd);
Customer changeBy(ChangeCustomerDetails cmd);
}
3 changes: 0 additions & 3 deletions app/src/main/resources/adapter/persistence/bundle-init.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,4 @@
<!-- DDL -->
<include file="adapter/persistence/ddl/customers-ddl-1.0.0.xml"/>

<!-- DML -->
<include file="adapter/persistence/dml/customers-demo-dml-1.0.0.xml"/>

</databaseChangeLog>

This file was deleted.

2 changes: 2 additions & 0 deletions app/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
logging:
level:
root: INFO
file:
path: logs

spring:
h2:
Expand Down
Loading

0 comments on commit b0791bc

Please sign in to comment.