最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - DTO at hexagonal architecture - Stack Overflow

programmeradmin3浏览0评论

I am recently working on hexagonal architecture test with java and spring boot, and i am trying to implement DTOs, i have a service class and this class inherits from four interfaces, ICreateProduct, IUpdateProduct, IRetrieveProduct and IDeleteProduct. The problem is that when i try to convert my domain models to DTOs to map the data i get an error, and i need change the methods to reurn DTOs instead of interface methods to resolve it. My question is for all those who have professional experience in hexagonal architecture, is it correct to change service methods to methods that return DTOs and only use the interfaces as dependency injection?

This is my code:

public class ProductService implements ICreateProduct, IUpdateProduct, IDeleteProduct{
private final ICreateProduct createProduct;
private final IUpdateProduct updateProduct;
private final IRetrieveProduct retrieveProduct;
private final IDeleteProduct deleteProduct;

    public ProductService(ICreateProduct createProduct, IUpdateProduct updateProduct, IRetrieveProduct retrieveProduct, IDeleteProduct deleteProduct) {
        this.createProduct = createProduct;
        this.updateProduct = updateProduct;
        this.retrieveProduct = retrieveProduct;
        this.deleteProduct = deleteProduct;
    }
    
    @Override
    public boolean deleteProductById(Long id) {
        return deleteProduct.deleteProductById(id);
    }
    
    public GetAllProductsDTO getAllProducts() {
        List<ProductDto> products = retrieveProduct.getAllProducts().stream().map(ProductMapper::toDto).collect(Collectors.toList());
        //return retrieveProduct.getAllProducts().stream().map(this::convertToDTO).collect(Collectors.toList());
        return new GetAllProductsDTO(products);
    }
    
    public ProductDto getProductById(Long id) {
        Product product = retrieveProduct.getProductById(id).orElseThrow(() -> new RuntimeException("¡Product not found!"));
        return ProductMapper.toDto(product);
    }
    
    @Override
    public Optional<Product> updateProduct(Long id, Product product) {
        return updateProduct.updateProduct(id, product);
    }
    
    @Override
    public Product createProduct(Product product) {
        return createProduct.createProduct(product);
    }

}

And my DTOs, i am using records for that.

public record GetAllProductsDTO(List<ProductDto> products) {

}
public record ProductDto(Long id, String name, double price) {

}

These are the folders of my project, this is how it is structured.

I am recently working on hexagonal architecture test with java and spring boot, and i am trying to implement DTOs, i have a service class and this class inherits from four interfaces, ICreateProduct, IUpdateProduct, IRetrieveProduct and IDeleteProduct. The problem is that when i try to convert my domain models to DTOs to map the data i get an error, and i need change the methods to reurn DTOs instead of interface methods to resolve it. My question is for all those who have professional experience in hexagonal architecture, is it correct to change service methods to methods that return DTOs and only use the interfaces as dependency injection?

This is my code:

public class ProductService implements ICreateProduct, IUpdateProduct, IDeleteProduct{
private final ICreateProduct createProduct;
private final IUpdateProduct updateProduct;
private final IRetrieveProduct retrieveProduct;
private final IDeleteProduct deleteProduct;

    public ProductService(ICreateProduct createProduct, IUpdateProduct updateProduct, IRetrieveProduct retrieveProduct, IDeleteProduct deleteProduct) {
        this.createProduct = createProduct;
        this.updateProduct = updateProduct;
        this.retrieveProduct = retrieveProduct;
        this.deleteProduct = deleteProduct;
    }
    
    @Override
    public boolean deleteProductById(Long id) {
        return deleteProduct.deleteProductById(id);
    }
    
    public GetAllProductsDTO getAllProducts() {
        List<ProductDto> products = retrieveProduct.getAllProducts().stream().map(ProductMapper::toDto).collect(Collectors.toList());
        //return retrieveProduct.getAllProducts().stream().map(this::convertToDTO).collect(Collectors.toList());
        return new GetAllProductsDTO(products);
    }
    
    public ProductDto getProductById(Long id) {
        Product product = retrieveProduct.getProductById(id).orElseThrow(() -> new RuntimeException("¡Product not found!"));
        return ProductMapper.toDto(product);
    }
    
    @Override
    public Optional<Product> updateProduct(Long id, Product product) {
        return updateProduct.updateProduct(id, product);
    }
    
    @Override
    public Product createProduct(Product product) {
        return createProduct.createProduct(product);
    }

}

And my DTOs, i am using records for that.

public record GetAllProductsDTO(List<ProductDto> products) {

}
public record ProductDto(Long id, String name, double price) {

}

These are the folders of my project, this is how it is structured.

Share Improve this question edited Mar 23 at 19:53 Frank2497 asked Mar 19 at 14:37 Frank2497Frank2497 92 bronze badges 8
  • 3 If you change the port interfaces to return DTOs, you leak adapter-specific concerns (DTOs) into the domain layer, violating hexagonal principles. – K.Nicholas Commented Mar 19 at 20:38
  • 1 Please elaborate on the "i get an error". Could you provide your code "giving an error" and your dependency tree. A minimal reproducible example would be perfect. – Vincent C. Commented Mar 19 at 20:44
  • @K.Nicholas I didn't change the interface ports to return DTOs, but as in the example, the service implemented the IRetrieveProduct interfaces as a contract, but when creating the DTOs I had to change the RetrieveProduct methods within the service to methods that would return the DTOs to the controller. – Frank2497 Commented Mar 20 at 0:23
  • 2 could you add a architecture image? that would greatly improve the question. – Martin Frank Commented Mar 20 at 14:17
  • 1 hello its me again, thanks for sharing your project structure, but i would like to see a view of the concepts, of the ideas, of the architecture to better understand your needs and problems - maybe you have an UML diagramm representing the idea of your app? – Martin Frank Commented Mar 24 at 8:21
 |  Show 3 more comments

1 Answer 1

Reset to default 0

Yes, you can return DTOs to the controller, but it is better to return a common response body from the controller. Here's an example of how you can implement it:

public interface CommonService <T> {

    T getById(String id);

    List<T> getAll();

    T create(T k);

    T update(String id,T t) throws Exception;

    PageableDto<T> search(Object o);

    void deleteById(String id) throws Exception;

}

Then you can use this in your controller like this:

@RequestMapping("/test")
@RestController
public class Controller {

    private final CommonService<TestDTO> commonService;

    @PostMapping("")
    public ApiCommonResponse create(@RequestBody  TestDTO testDto) {
        return new ApiCommonResponse(commonService.create(activityDto), 
            "200", "", "Data Created Successfully");
    }

}

And ApiCommonResponse is

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiCommonResponse {
    private Object data;
    private String timestamp=new Date().toString();
    private String status;
    private String error;
    private String message;
}
发布评论

评论列表(0)

  1. 暂无评论