Usando vários objetos de origem com MapStruct
1. Visão geral
Neste tutorial, veremos como usar vários objetos de origem comMapStruct.
2. Objeto de origem única
O caso de uso mais comum para o MapStruct é mapear um objeto para outro. Vamos supor que temos uma classeCustomer:
class Customer {
private String firstName;
private String lastName;
// getters and setters
}
Suponhamos ainda que haja umCustomerDto correspondente:
class CustomerDto {
private String forename;
private String surname;
// getters and setters
}
Agora podemos definir um mapeador que mapeia um objetoCustomer para um objetoCustomerDto:
@Mapper
public interface CustomerDtoMapper {
@Mapping(source = "firstName", target = "forename")
@Mapping(source = "lastName", target = "surname")
CustomerDto from(Customer customer);
}
3. Vários objetos de origem
Sometimes we want the target object having properties from multiple source objects. Vamos imaginar que escrevemos um aplicativo de compras.
Precisamos construir um endereço de entrega para enviar nossos produtos:
class DeliveryAddress {
private String forename;
private String surname;
private String street;
private String postalcode;
private String county;
// getters and setters
}
Cada cliente pode ter vários endereços. Um pode ser um endereço residencial. Outro pode ser um endereço comercial:
class Address {
private String street;
private String postalcode;
private String county;
// getters and setters
}
Agora precisamos de um mapeador que crie o endereço de entrega de um cliente e um de seus endereços. O MapStruct suporta isso tendo vários objetos de origem:
@Mapper
interface DeliveryAddressMapper {
@Mapping(source = "customer.firstName", target = "forename")
@Mapping(source = "customer.lastName", target = "surname")
@Mapping(source = "address.street", target = "street")
@Mapping(source = "address.postalcode", target = "postalcode")
@Mapping(source = "address.county", target = "county")
DeliveryAddress from(Customer customer, Address address);
}
Vamos ver isso em ação escrevendo um pequeno teste:
// given a customer
Customer customer = new Customer().setFirstName("Max")
.setLastName("Powers");
// and some address
Address homeAddress = new Address().setStreet("123 Some Street")
.setCounty("Nevada")
.setPostalcode("89123");
// when calling DeliveryAddressMapper::from
DeliveryAddress deliveryAddress = deliveryAddressMapper.from(customer, homeAddress);
// then a new DeliveryAddress is created, based on the given customer and his home address
assertEquals(deliveryAddress.getForename(), customer.getFirstName());
assertEquals(deliveryAddress.getSurname(), customer.getLastName());
assertEquals(deliveryAddress.getStreet(), homeAddress.getStreet());
assertEquals(deliveryAddress.getCounty(), homeAddress.getCounty());
assertEquals(deliveryAddress.getPostalcode(), homeAddress.getPostalcode());
When we have more than one parameter, we can address them with dot-notation within the @Mapping annotation. Por exemplo, para endereçar a propriedadefirstName do parâmetro denominadocustomer, simplesmente escrevemos “customer.firstName“.
No entanto, não estamos limitados a dois objetos de origem. Any number will do.
4. Atualize objetos existentes com@MappingTarget
Até agora, tínhamos mapeadores que criam novas instâncias da classe de destino. Com vários objetos de origem, agora também podemos fornecer uma instância a ser atualizada.
Por exemplo, vamos supor que desejamos atualizar as propriedades relacionadas ao cliente de um endereço de entrega. Tudo o que precisamos é ter um dos parâmetros do mesmo tipo que o retornado pelo método e anotá-lo com@MappingTarget:
@Mapper
interface DeliveryAddressMapper {
@Mapping(source = "address.postalcode", target = "postalcode")
@Mapping(source = "address.county", target = "county")
DeliveryAddress updateAddress(@MappingTarget DeliveryAddress deliveryAddress, Address address);
}
Então, vamos fazer um teste rápido com uma instância deDeliveryAddress:
// given a delivery address
DeliveryAddress deliveryAddress = new DeliveryAddress().setForename("Max")
.setSurname("Powers")
.setStreet("123 Some Street")
.setCounty("Nevada")
.setPostalcode("89123");
// and some new address
Address newAddress = new Address().setStreet("456 Some other street")
.setCounty("Arizona")
.setPostalcode("12345");
// when calling DeliveryAddressMapper::updateAddress
DeliveryAddress updatedDeliveryAddress = deliveryAddressMapper.updateAddress(deliveryAddress, newAddress);
// then the *existing* delivery address is updated
assertSame(deliveryAddress, updatedDeliveryAddress);
assertEquals(deliveryAddress.getStreet(), newAddress.getStreet());
assertEquals(deliveryAddress.getCounty(), newAddress.getCounty());
assertEquals(deliveryAddress.getPostalcode(), newAddress.getPostalcode());
5. Conclusão
MapStruct nos permite passar mais de um parâmetro de origem para métodos de mapeamento. Por exemplo, isso é útil quando queremos combinar várias entidades em uma.
Outro caso de uso é fazer com que o próprio objeto de destino seja um dos parâmetros de origem. Usando a anotação@MappingTarget, o objeto fornecido pode ser atualizado no local.
Certifique-se de verificar todas essas amostrasover on GitHub.