Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Commit

Permalink
refactor: switch the product classes to clean architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasmzsouza committed Jul 19, 2024
1 parent d83e9ee commit 0ba9dd0
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 117 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package br.com.fiap.grupo30.fastfood.domain.repositories;

import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import java.util.List;

public interface ProductRepository {

List<ProductDTO> findProductsByCategoryId(Long categoryId);
List<Product> findProductsByCategoryId(Long categoryId);

ProductDTO findById(Long id);
Product findById(Long id);

ProductDTO insert(ProductDTO dto);
Product insert(Product product);

ProductDTO update(Long id, ProductDTO dto);
Product update(Long id, Product product);

void delete(Long id);
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package br.com.fiap.grupo30.fastfood.domain.usecases.product;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import org.springframework.stereotype.Component;
import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;

@Component
public class CreateProductUseCase {

private final ProductRepository productRepository;
private final ProductGateway productGateway;

public CreateProductUseCase(ProductRepository productRepository) {
this.productRepository = productRepository;
public CreateProductUseCase(ProductGateway productGateway) {
this.productGateway = productGateway;
}

public ProductDTO execute(ProductDTO product) {
return productRepository.insert(product);
public Product execute(Product product) {
return productGateway.insert(product);
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package br.com.fiap.grupo30.fastfood.domain.usecases.product;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import org.springframework.stereotype.Component;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;

@Component
public class DeleteProductUseCase {

private final ProductRepository productRepository;
private final ProductGateway productGateway;

public DeleteProductUseCase(ProductRepository productRepository) {
this.productRepository = productRepository;
public DeleteProductUseCase(ProductGateway productGateway) {
this.productGateway = productGateway;
}

public void execute(Long id) {
productRepository.delete(id);
productGateway.delete(id);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package br.com.fiap.grupo30.fastfood.domain.usecases.product;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import org.springframework.stereotype.Component;
import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;

@Component
public class GetProductUseCase {

private final ProductRepository productRepository;
private final ProductGateway productGateway;

public GetProductUseCase(ProductRepository productRepository) {
this.productRepository = productRepository;
public GetProductUseCase(ProductGateway productGateway) {
this.productGateway = productGateway;
}

public ProductDTO execute(Long id) {
return productRepository.findById(id);
public Product execute(Long id) {
return productGateway.findById(id);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package br.com.fiap.grupo30.fastfood.domain.usecases.product;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;
import java.util.List;
import org.springframework.stereotype.Component;

@Component
public class ListProductsByCategoryUseCase {

private final ProductRepository productRepository;
private final ProductGateway productGateway;

public ListProductsByCategoryUseCase(ProductRepository productRepository) {
this.productRepository = productRepository;
public ListProductsByCategoryUseCase(ProductGateway productGateway) {
this.productGateway = productGateway;
}

public List<ProductDTO> execute(Long categoryId) {
return productRepository.findProductsByCategoryId(categoryId);
public List<Product> execute(Long categoryId) {
return productGateway.findProductsByCategoryId(categoryId);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package br.com.fiap.grupo30.fastfood.domain.usecases.product;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import org.springframework.stereotype.Component;
import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;

@Component
public class UpdateProductUseCase {

private final ProductRepository productRepository;
private final ProductGateway productGateway;

public UpdateProductUseCase(ProductRepository productRepository) {
this.productRepository = productRepository;
public UpdateProductUseCase(ProductGateway productGateway) {
this.productGateway = productGateway;
}

public ProductDTO execute(Long id, ProductDTO product) {
return productRepository.update(id, product);
public Product execute(Long id, Product product) {
return productGateway.update(id, product);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package br.com.fiap.grupo30.fastfood.infrastructure.configuration;

import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.domain.usecases.product.*;
import br.com.fiap.grupo30.fastfood.infrastructure.gateways.ProductGateway;
import br.com.fiap.grupo30.fastfood.infrastructure.persistence.repositories.JpaProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.mapper.impl.ProductEntityMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ProductConfiguration {

@Bean
public ProductRepository productRepository(
JpaProductRepository jpaProductRepository, ProductEntityMapper productEntityMapper) {
return new ProductGateway(jpaProductRepository, productEntityMapper);
}

@Bean
public ListProductsByCategoryUseCase listProductsByCategoryUseCase(
ProductGateway productGateway) {
return new ListProductsByCategoryUseCase(productGateway);
}

@Bean
public GetProductUseCase getProductUseCase(ProductGateway productGateway) {
return new GetProductUseCase(productGateway);
}

@Bean
public CreateProductUseCase createProductUseCase(ProductGateway productGateway) {
return new CreateProductUseCase(productGateway);
}

@Bean
public UpdateProductUseCase updateProductUseCase(ProductGateway productGateway) {
return new UpdateProductUseCase(productGateway);
}

@Bean
public DeleteProductUseCase deleteProductUseCase(ProductGateway productGateway) {
return new DeleteProductUseCase(productGateway);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package br.com.fiap.grupo30.fastfood.infrastructure.gateways;

import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.domain.repositories.ProductRepository;
import br.com.fiap.grupo30.fastfood.infrastructure.persistence.entities.ProductEntity;
import br.com.fiap.grupo30.fastfood.infrastructure.persistence.repositories.JpaProductRepository;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import br.com.fiap.grupo30.fastfood.presentation.presenters.exceptions.DatabaseException;
import br.com.fiap.grupo30.fastfood.presentation.presenters.exceptions.ResourceNotFoundException;
import br.com.fiap.grupo30.fastfood.presentation.presenters.mapper.impl.ProductDTOMapper;
import br.com.fiap.grupo30.fastfood.presentation.presenters.mapper.impl.ProductMapper;
import br.com.fiap.grupo30.fastfood.presentation.presenters.mapper.impl.ProductEntityMapper;
import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import java.util.Optional;
Expand All @@ -21,52 +20,48 @@
public class ProductGateway implements ProductRepository {

private final JpaProductRepository jpaProductRepository;
private final ProductMapper productMapper;
private final ProductDTOMapper productDTOMapper;
private final ProductEntityMapper productEntityMapper;

@Autowired
public ProductGateway(
JpaProductRepository jpaProductRepository,
ProductMapper productMapper,
ProductDTOMapper productDTOMapper) {
JpaProductRepository jpaProductRepository, ProductEntityMapper productEntityMapper) {
this.jpaProductRepository = jpaProductRepository;
this.productMapper = productMapper;
this.productDTOMapper = productDTOMapper;
this.productEntityMapper = productEntityMapper;
}

@Override
@Transactional(readOnly = true)
public List<ProductDTO> findProductsByCategoryId(Long categoryId) {
public List<Product> findProductsByCategoryId(Long categoryId) {
Long category = categoryId == 0 ? null : categoryId;
return jpaProductRepository.findProductsByCategoryId(category).stream()
.map(entity -> new ProductDTO(productMapper.mapFrom(entity)))
.map(this.productEntityMapper::mapFrom)
.toList();
}

@Override
@Transactional(readOnly = true)
public ProductDTO findById(Long id) {
public Product findById(Long id) {
Optional<ProductEntity> obj = jpaProductRepository.findById(id);
ProductEntity entity =
obj.orElseThrow(() -> new ResourceNotFoundException("Entity not found"));
return new ProductDTO(productMapper.mapFrom(entity));
return this.productEntityMapper.mapFrom(entity);
}

@Override
@Transactional
public ProductDTO insert(ProductDTO dto) {
ProductEntity entity = jpaProductRepository.save(productDTOMapper.mapTo(dto));
return new ProductDTO(productMapper.mapFrom(entity));
public Product insert(Product product) {
ProductEntity entity = jpaProductRepository.save(productEntityMapper.mapTo(product));
return this.productEntityMapper.mapFrom(entity);
}

@Override
@Transactional
public ProductDTO update(Long id, ProductDTO dto) {
public Product update(Long id, Product product) {
try {
ProductEntity entity = jpaProductRepository.getReferenceById(id);
productDTOMapper.updateEntityFromDTO(entity, dto);
productEntityMapper.updateEntityFromProduct(entity, product);
entity = jpaProductRepository.save(entity);
return new ProductDTO(productMapper.mapFrom(entity));
return this.productEntityMapper.mapFrom(entity);
} catch (EntityNotFoundException e) {
throw new ResourceNotFoundException("Id not found " + id, e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package br.com.fiap.grupo30.fastfood.presentation.controllers;

import br.com.fiap.grupo30.fastfood.domain.entities.Product;
import br.com.fiap.grupo30.fastfood.domain.usecases.product.*;
import br.com.fiap.grupo30.fastfood.presentation.presenters.dto.ProductDTO;
import br.com.fiap.grupo30.fastfood.presentation.presenters.mapper.impl.ProductDTOMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand All @@ -25,19 +27,23 @@ public class ProductController {
private final UpdateProductUseCase updateProductUseCase;
private final DeleteProductUseCase deleteProductUseCase;

private final ProductDTOMapper productDTOMapper;

@Autowired
public ProductController(
ListProductsByCategoryUseCase listProductsByCategoryUseCase,
GetProductUseCase getProductUseCase,
CreateProductUseCase createProductUseCase,
UpdateProductUseCase updateProductUseCase,
DeleteProductUseCase deleteProductUseCase) {
DeleteProductUseCase deleteProductUseCase,
ProductDTOMapper productDTOMapper) {

this.listProductsByCategoryUseCase = listProductsByCategoryUseCase;
this.getProductUseCase = getProductUseCase;
this.createProductUseCase = createProductUseCase;
this.updateProductUseCase = updateProductUseCase;
this.deleteProductUseCase = deleteProductUseCase;
this.productDTOMapper = productDTOMapper;
}

@GetMapping
Expand All @@ -48,7 +54,10 @@ public ProductController(
+ "via RequestParam. i.e., ?categoryId=1")
public ResponseEntity<List<ProductDTO>> findProductsByCategoryId(
@RequestParam(value = "categoryId", defaultValue = "0") Long categoryId) {
List<ProductDTO> list = this.listProductsByCategoryUseCase.execute(categoryId);
List<ProductDTO> list =
this.listProductsByCategoryUseCase.execute(categoryId).stream()
.map(this.productDTOMapper::mapTo)
.toList();
return ResponseEntity.ok().body(list);
}

Expand All @@ -57,7 +66,7 @@ public ResponseEntity<List<ProductDTO>> findProductsByCategoryId(
summary = "Get a product by ID",
description = "Retrieve a specific product based on its ID")
public ResponseEntity<ProductDTO> findProductById(@PathVariable Long id) {
ProductDTO dto = this.getProductUseCase.execute(id);
ProductDTO dto = this.productDTOMapper.mapTo(this.getProductUseCase.execute(id));
return ResponseEntity.ok().body(dto);
}

Expand All @@ -66,7 +75,9 @@ public ResponseEntity<ProductDTO> findProductById(@PathVariable Long id) {
summary = "Create a new product",
description = "Create a new product and return the created product's data")
public ResponseEntity<ProductDTO> createProduct(@RequestBody @Valid ProductDTO dto) {
ProductDTO dtoCreated = this.createProductUseCase.execute(dto);
Product domainObj = this.productDTOMapper.mapFrom(dto);
ProductDTO dtoCreated =
this.productDTOMapper.mapTo(this.createProductUseCase.execute(domainObj));
URI uri =
ServletUriComponentsBuilder.fromCurrentRequest()
.path(PATH_VARIABLE_ID)
Expand All @@ -81,7 +92,9 @@ public ResponseEntity<ProductDTO> createProduct(@RequestBody @Valid ProductDTO d
description = "Update the data of an existing product based on its ID")
public ResponseEntity<ProductDTO> updateProduct(
@PathVariable Long id, @RequestBody @Valid ProductDTO dto) {
ProductDTO dtoUpdated = this.updateProductUseCase.execute(id, dto);
Product domainObj = this.productDTOMapper.mapFrom(dto);
ProductDTO dtoUpdated =
this.productDTOMapper.mapTo(this.updateProductUseCase.execute(id, domainObj));
return ResponseEntity.ok().body(dtoUpdated);
}

Expand Down
Loading

0 comments on commit 0ba9dd0

Please sign in to comment.