Em aplicativos Java,we may wish to copy values from one type of Java bean to another. Para evitar um código longo e sujeito a erros, podemos usar um mapeador de bean comoMapStruct.
Embora o mapeamento de campos idênticos com nomes de campo idênticos seja muito simples,we often encounter mismatched beans. Neste tutorial, veremos como MapStruct lida com o mapeamento parcial.
2. Mapeamento
MapStruct é um processador de anotação Java. Portanto, tudo o que precisamos fazer é definir a interface do mapeador e declarar métodos de mapeamento. MapStruct will generate an implementation of this interface during compilation.
Para simplificar, vamos começar com duas classes com os mesmos nomes de campo:
public class CarDTO {
private int id;
private String name;
}
public class Car {
private int id;
private String name;
}
@Test
public void givenCarEntitytoCar_whenMaps_thenCorrect() {
Car entity = new Car();
entity.setId(1);
entity.setName("Toyota");
CarDTO carDto = CarMapper.INSTANCE.carToCarDTO(entity);
assertThat(carDto.getId()).isEqualTo(entity.getId());
assertThat(carDto.getName()).isEqualTo(entity.getName());
}
3. Propriedades não mapeadas
Como o MapStruct opera em tempo de compilação, pode ser mais rápido que uma estrutura de mapeamento dinâmico. Ele também podegenerate error reports if mappings are incomplete - ou seja, se nem todas as propriedades de destino forem mapeadas:
Embora este seja um aviso útil no caso de um acidente, podemos preferir lidar com as coisas de maneira diferente se os campos estiverem faltando de propósito.
Vamos explorar isso com um exemplo de mapeamento de dois objetos simples:
public class DocumentDTO {
private int id;
private String title;
private String text;
private List comments;
private String author;
}
public class Document {
private int id;
private String title;
private String text;
private Date modificationTime;
}
Temos campos exclusivos em ambas as classes que não devem ser preenchidos durante o mapeamento. Eles são:
comments emDocumentDTO
author emDocumentDTO
modificationTime emDocument
Se definirmos uma interface do mapeador, isso resultará em mensagens de aviso durante a construção:
Aqui, fornecemos o nome do campo comotargete definimosignore paratrue para mostrar que não é necessário para o mapeamento.
No entanto, essa técnica não é conveniente para alguns casos. Podemos achar difícil usar, por exemplo, ao usar modelos grandes com um grande número de campos.
5. Política de destino não mapeada
Para tornar as coisas mais claras e o código mais legível, podemosspecify the unmapped target policy.
Para fazer isso, usamos o MapStructunmappedTargetPolicy para fornecer nosso comportamento desejado quando não há campo de origem para o mapeamento:
ERROR: qualquer propriedade de destino não mapeada falhará na compilação - isso pode nos ajudar a evitar campos acidentalmente não mapeados
WARN: (padrão) mensagens de aviso durante a construção
IGNORE: sem saída ou erros
In order to ignore unmapped properties and get no output warnings, devemosassign the IGNORE value to the unmappedTargetPolicy. Existem várias maneiras de fazer isso, dependendo do propósito.
5.1. Defina uma política em cadaMapper
Podemos definir a anotaçãothe unmappedTargetPolicy to the@Mapper. Como resultado, todos os seus métodos ignoram propriedades não mapeadas:
Podemos ignorar propriedades não mapeadas em vários mapeadores configurandothe unmappedTargetPolicy via@MapperConfig para compartilhar uma configuração entre vários mapeadores.
Primeiro, criamos uma interface anotada:
@MapperConfig(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface IgnoreUnmappedMapperConfig {
}
Em seguida, aplicamos essa configuração compartilhada a um mapeador:
Devemos observar que este é um exemplo simples que mostra o uso mínimo de@MapperConfig, que pode não parecer muito melhor do que definir a política em cada mapeador. A configuração compartilhada se torna muito útil quando há várias configurações para padronizar em vários mapeadores.
5.3. Opções de configuração
Finalmente, podemos configurar as opções do processador de anotação do gerador de código MapStruct. Ao usarMaven, podemos passar as opções do processador usando o parâmetrocompilerArgs do plug-in do processador:
Neste exemplo, estamos ignorando as propriedades não mapeadas em todo o projeto.
6. A Ordem de Precedência
Vimos várias maneiras que podem nos ajudar a lidar com mapeamentos parciais e ignorar completamente as propriedades não mapeadas. Também vimos como aplicá-los independentemente em um mapeador, maswe can also combine them.
Vamos supor que temos uma grande base de código de beans e mapeadores com a configuração MapStruct padrão. Não queremos permitir mapeamentos parciais, exceto em alguns casos. Podemos facilmente adicionar mais campos a um bean ou a sua contrapartida mapeada e obter um mapeamento parcial sem notá-lo.
Portanto, é provavelmente uma boa ideia adicionar uma configuração global por meio da configuração do Maven para fazer a compilação falhar no caso de mapeamentos parciais.
Agora, para permitir propriedades não mapeadas em alguns de nossos mapeadores eoverride the global behavior, podemos combinar as técnicas, tendo em mente a ordem de precedência (do maior para o menor):
Ignorando Campos Específicos no Nível do Método do Mapeador
A política no mapeador
O MapperConfig compartilhado
A configuração global
7. Conclusão
Neste tutorial,we looked at how to configure MapStruct to ignore unmapped properties.
Primeiro, analisamos o que as propriedades não mapeadas significam para o mapeamento. Então vimos como mapeamentos parciais poderiam ser permitidos sem erros, de algumas maneiras diferentes.
Por fim, aprendemos a combinar essas técnicas, tendo em mente a ordem de precedência.
Como sempre, o código deste tutorial está disponívelover on GitHub.