É bom que uma estrutura como o SpringBoot possa fazer tantas coisas por você.
Você só precisa de uma classe de entidade JPA mais uma interface de repositório simples e o SpringData oferece tudo o que você precisa para operações típicas de banco de dados CRUD.
Você escreve uma classe de controlador REST simples e tem uma API REST em execução, certo?
Ei, mas você esqueceu de escrever um DTO! Mas por que você realmente precisa dele quando seu aplicativo poderia funcionar sem ele?
Certamente existem alguns motivos gerais:
Mas outras coisas estranhas também podem acontecer. Vou mostrar um exemplo estranho baseado na minha experiência.
Este repositório GitHub contém um aplicativo simples que funciona sem os DTOs. Existe uma entidade Usuário, cada Usuário pode ter múltiplas Transações. Temos ainda um bean Service entre o repositório e o RestController, capturando possíveis exceções de acesso ao banco de dados.
Como queremos fazer uma aplicação pronta para produção, não queremos que o Hibernate gere o DDL. Em vez disso, temos um schema.sql que cria as tabelas (mais tarde podemos mudar para Flyway ou Liquibase). Para nosso exemplo simples, também temos um data.sql para que nossas tabelas não fiquem vazias.
Quando executamos o aplicativo e chamamos o endpoint da API em http://localhost:8080/users, obtemos o JSON esperado contendo os usuários e suas transações.
Agora vamos prestar atenção nas duas linhas de código da classe Transaction, marcadas como //!!
@JsonIgnorar //!!
O primeiro cheiro é que na classe Transaction tivemos que adicionar a anotação @JsonIgnore à referência do usuário. Sem essa anotação, a serialização JSON falha devido à recursão infinita.
Agora vamos imaginar que alguém comete um erro ao adicionar outro campo (descrição) à entidade Transação, mas se esquece de ajustar as instruções SQL (ou executa a aplicação em um ambiente onde a alteração do esquema não foi aplicada).
]
descrição da string privada;//!!
Claro, agora a chamada da API falha. Mas veja o tratamento de erros! A cláusula catch dentro do UserService não funciona conforme o esperado. Em vez disso, podemos ver um rastreamento de pilha estranho no log:
GlobalExceptionHandler: Erro inesperado org.springframework.http.converter.HttpMessageNotWritableException: Não foi possível escrever JSON:
Uma vez vi essa situação (claramente, com um aplicativo muito maior que este exemplo) e demorei um pouco para entender por que a exceção SQL escapou do serviço e por que estava recebendo uma HttpMessageNotWritableException. Você consegue ver?
O que acontece é que a classe UserService (através do UserRepository) consulta apenas a tabela do banco de dados USERS. As entidades Transaction não fazem parte do resultado devido ao carregamento lento padrão do Hibernate. Somente quando o desserializador Jackson tenta criar JSON a partir da instância User, ele invoca seu método getTransactions que faz o Hibernate buscar as entidades Transaction.
É por isso que obtemos um stacktrace estranho combinando coisas JSON e SQL. A exceção é capturada pelo GlobalExceptionHandler que não sabe o que fazer com ela, por isso a mensagem de log é "Erro inesperado".
Espero que este pequeno exercício faça você entender mais profundamente como é perigoso permitir que diferentes camadas de sua aplicação se misturem. Ver apenas os cenários de "dias ensolarados" do seu aplicativo enquanto ele ainda é pequeno pode levar alguns desenvolvedores a continuar fazendo a coisa errada até que seja tarde demais.
Você não precisa escrever o código clichê mapeando os campos entre seu DTO e as outras camadas da sua aplicação. MapStruct pode fazer isso por você.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3