MapStructでの複数のソースオブジェクトの使用
1. 概要
このチュートリアルでは、MapStructで複数のソースオブジェクトを使用する方法を説明します。
2. 単一ソースオブジェクト
MapStructの最も一般的な使用例は、あるオブジェクトを別のオブジェクトにマップすることです。 Customerクラスがあると仮定します。
class Customer {
private String firstName;
private String lastName;
// getters and setters
}
対応するCustomerDtoがあるとさらに仮定しましょう。
class CustomerDto {
private String forename;
private String surname;
// getters and setters
}
これで、CustomerオブジェクトをCustomerDtoオブジェクトにマップするマッパーを定義できます。
@Mapper
public interface CustomerDtoMapper {
@Mapping(source = "firstName", target = "forename")
@Mapping(source = "lastName", target = "surname")
CustomerDto from(Customer customer);
}
3. 複数のソースオブジェクト
複数のソースオブジェクトからのプロパティを持つターゲットオブジェクトが必要な場合があります。ショッピングアプリケーションを作成するとします。
商品を発送するには、配送先住所を作成する必要があります。
class DeliveryAddress {
private String forename;
private String surname;
private String street;
private String postalcode;
private String county;
// getters and setters
}
各顧客は複数のアドレスを持つことができます。 1つは自宅の住所にすることができます。 もう1つは、職場の住所にすることができます。
class Address {
private String street;
private String postalcode;
private String county;
// getters and setters
}
ここで、顧客とそのアドレスの1つから配信アドレスを作成するマッパーが必要です。 MapStructは、複数のソースオブジェクトを持つことでこれをサポートします。
@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);
}
小さなテストを書いて、これが実際に動作していることを見てみましょう。
// 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());
ただし、2つのソースオブジェクトに限定されません。 任意の数でかまいません。
4. @MappingTargetで既存のオブジェクトを更新します
これまで、ターゲットクラスの新しいインスタンスを作成するマッパーがありました。 複数のソースオブジェクトを使用して、更新するインスタンスを提供できるようになりました。
たとえば、配送先住所の顧客関連のプロパティを更新するとします。 必要なのは、パラメーターの1つをメソッドによって返されるものと同じタイプにし、@MappingTargetで注釈を付けることだけです。
@Mapper
interface DeliveryAddressMapper {
@Mapping(source = "address.postalcode", target = "postalcode")
@Mapping(source = "address.county", target = "county")
DeliveryAddress updateAddress(@MappingTarget DeliveryAddress deliveryAddress, Address address);
}
それでは、先に進んで、DeliveryAddressのインスタンスを使用して簡単なテストを行いましょう。
// 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. 結論
MapStructを使用すると、複数のソースパラメータをマッピングメソッドに渡すことができます。 たとえば、これは、複数のエンティティを1つに結合する場合に便利です。
もう1つのユースケースは、ターゲットオブジェクト自体をソースパラメータの1つにすることです。 @MappingTarget アノテーションを使用して、指定されたオブジェクトをその場で更新できます。
これらすべてのサンプルをGitHubで確認してください。