Map Struct - Criando objetos DTOs de forma mais elegante

Neste artigo será apresentado a biblioteca Map Struct que permite criar objetos dtos e serializa-los de forma mais elegante, simples e prática.
Data Transfer Object, comumente conhecido como DTO é um padrão de projetos muito utilizado em várias linguagens de programação. É destinado para o transporte de dados entre diferentes camadas do sistema. A proposta é possuir uma classe mais simples e leve para melhorar a comunicação e otimizar o processamento.
Sobre sua aplicabilidade
O padrão DTO, resolver vários problemas, um deles é onde possuirmos o cadastro de uma entidade, mas algumas informações não necessariamente são obrigatórias ou necessárias, nesse caso, podemos criar uma classe secundária onde tenha os campos necessários e depois realizarmos a conversão/mapeamento para a entidade. Se procurarmos algum exemplo especificamente com Java, nos deparamos com os seguintes exemplos. Onde existe uma classe DTO e dentro dela, temos um construtor fazendo o de-para.
Exemplo prático
Para este exemplo, vamos imaginar que o nosso sistema é composto por uma tela de um sistema de cadastro de usuários, no módulo de cadastro de usuário, certos campos não são obrigatórios no envio da requisição. A classe abaixo representa a entidade User.
Contudo, o sistema não necessita que no momento de criação seja informado o id do cliente e se o usuário está ativo ou não, para isso criamos um DTO, um objeto mais simples para representar o nosso cadastro. A classe abaixo representa o nosso UserDTO.
Bom, na teoria, o nosso DTO está funcional e atendendo a necessidade de cadastro de usuários, mas em uma ensolarada manhã, a necessidade do cliente muda e o Product Owner chega na sua mesa informando que nesta tela, onde temos o cadastro de usuário torna-se necessário informar mais informações do cliente, como número do pedido, cidade e estado.
Agora temos um cenário onde toda e qualquer alteração precisa incrementar o nosso construtor UserDTO convertToUser(User user)
. Nesse cenário, temos seis propriedades, até aí tudo bem. Mas se considerarmos, a tendência do software de ir mudando a necessidade da tela de cadastro de usuário ficará muito inviável manter esse construtor, pois ele não irá parar de crescer ferido o princípio SOLID Open-closed principle, onde define que uma entidade deverá estar aberta para extensão, mas fechada para modificação.
Nessa parte que entra a lib MapStruct
, a proposta dela é simplificar a implementação de mapeamento entre tipos. É rápido, seguro e fácil de implementar e entender. A utilização e serialização de DTO/Entidades é simplificada com o uso dessa dependência.
Para iniciar a implementação, é necessário importa-la ao projeto na documentação oficial é demostrado essa inclusão;
1
2
3
4
5
6
7
dependencies {
...
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}
Uma abordagem que particularmente eu curto é a utilização de static factory method
juntamente com uma classe abstract
, onde a conversão ficaria da seguinte forma;
Assim a nossa classe de serviço terá uma única instância do Mapper e a leitura fica bem mais agradável;
Essa implementação pode ser utilizada em várias camadas e tornará esse tipo de conversão muito fácil.
Encerramento
Foi apresentado a utilização do MapStruct
para mapeamento de DTOs com o uso de static factory method
. Com essa abordagem, se surgir a necessidade de aumentar as propriedades da nossa tela de cadastro basta incluir as propriedades nas classes User
e UserDTO
. O construtor que poderia se tornar um godzilla já não existe nessa cenário. Ficando mais limpa e prática.
Na sequência, abordaremos um comparativo entre MapStruct
e a biblioteca ModelMapper
.
Código fonte
O código fonte está disponibilizado aqui.