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());

複数のパラメーターがある場合は、@Mappingアノテーション内のドット表記でそれらをアドレス指定できます。 たとえば、プロパティに対処するにはファーストネーム名前の付いたパラメータのお客様単に「 customer.firstName 「。

ただし、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で確認してください。