Crie DTOs em Java com uma única anotação e vá curtir a vida
Data Transfer Objects (DTOs) são uma excelente forma de definir quais são os dados que uma API precisa receber ou devolver. E com records do JDK 16, ficou bem mais fácil criá-los. Mas acho a criação de DTOs um processo bem repetitivo, cansativo e que gera custo de manutenção.
Considere que você tem uma classe/entidade Produto com os atributos Long id, String descricao, Marca marca. Se o id é gerado no banco, possivelmente você vai ter um DTO como:
record ProdutoDTO(Long id, String descricao, long marcaId) {}
Este DTO é enviado em requests (como insert e update) e responses de operações de consulta. Além do trabalho de ter que escrever praticamente os mesmos campos da entidade no DTO, alterações na estrutura da entidade precisam ser manualmente replicadas no DTO, não seguindo o princípio DRY.
Vejo muitos sistemas que ainda aumentam esse trabalho, criando um ProdutoRequestDAO, que só não tem o id (quando ele é gerado no banco) e um ProdutoResponseDAO, que é como o ProdutoDAO que mostrei. Ou seja, mais trabalho de manutenção.
A não ser que os DAOs tenham realmente uma estrutura muito diferente do mostrado, não vejo muito benefício nisso.
Adicionalmente, ainda temos um grande problema: a duplicação das anotações/lógica de validação entre o DAO e a entidade, trazendo inclusive inconsistências se uma regra for atualizada em apenas um lado. Por esses motivos, eu criei o DTOGen, uma lib para Java 21+ que usa processamento de anotações e geração de código para criar automaticamente DTO records para as entidades que você desejar.
A lib requer o uso de uma simples anotação @DTO para fazer a mágica, mas tem outras para permitir personalizar o record gerado. Uma das grandes vantagens da lib é que ela é validation-aware: ela copia todas as anotações do Hibernate Validator (como @NotNull) para os mesmos campos no DTO, evitando qualquer retrabalho.
Se você atualizar alguma entidade, basta fazer o build do projeto novamente pra atualizar os DTOs. O DTOGen ainda dispensa o uso de libs como MapStruct para mapear entre entidades e DTOs. Os DTOs são performáticos pois não dependem de Reflection ou qualquer tipo de dinamismo em runtime. O código gerado é simples e clean.
Para saber mais, acesse https://github.com/manoelcampos/dtogen
E aí? Como você tem criado seus DTOs? Qual abordagem usa? Quais vantagens e desvantagens? Se puder dar uma estrela no projeto lá no GitHub, agradeço 😉