1. 概要

この記事では、MapStructライブラリでカスタムマッパーを使用する方法を学習します。

MapStructライブラリは、JavaBeanタイプ間のマッピングに使用されます。 MapStruct でカスタムマッパーを使用することにより、デフォルトのマッピング方法をカスタマイズできます。

2. Mavenの依存関係

mapstructライブラリをMavenpom.xmlに追加しましょう。

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.3.1.Final</version> 
</dependency>

プロジェクトのターゲットフォルダー内で自動生成されたメソッドを表示するには、annotationProcessorPathsmaven-compiler-pluginプラグインに追加する必要があります。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct</artifactId>
                <version>1.3.1.Final</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

3. カスタムマッパー

カスタムマッパーは、特定の変換要件を解決するために使用されます。 これを実現するには、変換を実行するメソッドを定義する必要があります。 次に、メソッドについてMapStructに通知する必要があります。 最後に、MapStructはメソッドを呼び出して、ソースからターゲットへの変換を行います。

たとえば、ユーザーのボディマス指数(BMI)レポートを計算するアプリがあるとします。 BMIを計算するには、ユーザーの体格値を収集する必要があります。 インペリアル単位をメートル法に変換するには、カスタムマッパーメソッドを使用できます。

MapStructでカスタムマッパーを使用する方法は2つあります。 @MappingアノテーションのqualifiedByNameプロパティ内に入力してカスタムメソッドを呼び出すか、アノテーションを作成することができます。

始める前に、インペリアル値を保持するDTOクラスを定義する必要があります。

public class UserBodyImperialValuesDTO {
    private int inch;
    private int pound;
    // constructor, getters, and setters
}

次に、メトリック値を保持するDTOクラスを定義しましょう。

public class UserBodyValues {
    private double kilogram;
    private double centimeter;
    // constructor, getters, and setters
}

3.1. メソッドを使用したカスタムマッパー

カスタムマッパーの使用を開始するには、@Mapperアノテーションを使用してインターフェイスを作成しましょう。

@Mapper 
public interface UserBodyValuesMapper {
    //...
}

次に、必要な戻り型と変換する必要のある引数を使用してカスタムメソッドを作成しましょう。 カスタムマッパーメソッドについてMapStructに通知するには、valueパラメーターで@ Namedアノテーションを使用する必要があります。

@Mapper
public interface UserBodyValuesMapper {

    @Named("inchToCentimeter")
    public static double inchToCentimeter(int inch) {
        return inch * 2.54;
    }
 
    //...
}

最後に、@Mappingアノテーションを使用してマッパーインターフェイスメソッドを定義しましょう。 このアノテーション内で、ソースタイプ、ターゲットタイプ、および使用するメソッドについてMapStructに通知します。

@Mapper
public interface UserBodyValuesMapper {
    UserBodyValuesMapper INSTANCE = Mappers.getMapper(UserBodyValuesMapper.class);
    
    @Mapping(source = "inch", target = "centimeter", qualifiedByName = "inchToCentimeter")
    public UserBodyValues userBodyValuesMapper(UserBodyImperialValuesDTO dto);
    
    @Named("inchToCentimeter") 
    public static double inchToCentimeter(int inch) { 
        return inch * 2.54; 
    }
}

カスタムマッパーをテストしてみましょう。

UserBodyImperialValuesDTO dto = new UserBodyImperialValuesDTO();
dto.setInch(10);

UserBodyValues obj = UserBodyValuesMapper.INSTANCE.userBodyValuesMapper(dto);

assertNotNull(obj);
assertEquals(25.4, obj.getCentimeter(), 0);

3.2. 注釈付きのカスタムマッパー

アノテーション付きのカスタムマッパーを使用するには、@Namedアノテーションの代わりにアノテーションを定義する必要があります。 次に、@ MappingアノテーションのqualifiedByName parameterを指定して、新しく作成されたアノテーションについてMapStructに通知する必要があります。

注釈をどのように定義するかを見てみましょう。

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PoundToKilogramMapper {
}

@PoundToKilogramMapperアノテーションをpoundToKilogramメソッドに追加しましょう。

@PoundToKilogramMapper
public static double poundToKilogram(int pound) {
    return pound * 0.4535;
}

それでは、@Mappingアノテーションを使用してマッパーインターフェイスメソッドを定義しましょう。 マッピングアノテーション内で、ソースタイプ、ターゲットタイプ、および使用するアノテーションクラスについてMapStructに通知します。

@Mapper
public interface UserBodyValuesMapper {
    UserBodyValuesMapper INSTANCE = Mappers.getMapper(UserBodyValuesMapper.class);

    @Mapping(source = "pound", target = "kilogram", qualifiedBy = PoundToKilogramMapper.class)
    public UserBodyValues userBodyValuesMapper(UserBodyImperialValuesDTO dto);

    @PoundToKilogramMapper
    public static double poundToKilogram(int pound) {
        return pound * 0.4535;
    }
}

最後に、カスタムマッパーをテストしましょう。

UserBodyImperialValuesDTO dto = new UserBodyImperialValuesDTO();
dto.setPound(100);

UserBodyValues obj = UserBodyValuesMapper.INSTANCE.userBodyValuesMapper(dto);

assertNotNull(obj);
assertEquals(45.35, obj.getKilogram(), 0);

4. 結論

この記事では、MapStructライブラリでカスタムマッパーを使用する方法を学びました。

これらの例とテストの実装は、GitHub利用できます。