【MapStruct】よく使用するアノテーションを使いこなしてマッピングマスターになる(オブジェクト変換!!)

MapStructはJavaのオブジェクトマッピングライブラリであり、POJO(Plain Old Java Object)間でのマッピングを自動化するために使用されます

以下に、MapStructでよく使用されるアノテーションとそれらの実装例を10個挙げていきます


staticメソッドを実行する

Mapperクラスでstaticメソッドを使用するために、@Mapperアノテーションのimports属性を使用してメソッドをインポートします

// imports属性で使用したいクラスを指定します。
@Mapper(imports = Util.class)
public interface MyMapper {
    // Utilクラスのstaticメソッド(convert)を使用します。
    @Mapping(target = "targetField", expression = "java(Util.convert(source.getField()))")
    TargetClass map(SourceClass source);
}

@Mapper

インターフェースや抽象クラスに付与されます
MapStructがマッピングの実装を生成するためのマッパークラスを指定します

@Mapper
public interface MyMapper {
    TargetObject map(SourceObject source);
}

@Mapping

フィールドのマッピングを指定します
source属性にはソースオブジェクトのフィールド名、target属性にはターゲットオブジェクトのフィールド名を指定します

@Mapper
public interface MyMapper {
    @Mapping(source = "sourceField", target = "targetField")
    TargetObject map(SourceObject source);
}

@Mappings

複数の@Mappingアノテーションをまとめます
1つのメソッドに複数のフィールドをマッピングする場合に便利です

@Mapper
public interface MyMapper {
    @Mappings({
        @Mapping(source = "sourceField1", target = "targetField1"),
        @Mapping(source = "sourceField2", target = "targetField2")
    })
    TargetObject map(SourceObject source);
}

@MappingTarget

マッピングの対象となるターゲットオブジェクトを指定します

以下の場合、updateTargetメソッドはSourceObjectからTargetObjectへのマッピングを行いますが、@MappingTargetを使用してターゲットオブジェクトを指定しています
これにより、ターゲットオブジェクトが更新されます

@Mapper
public interface MyMapper {
    void updateTarget(SourceObject source, @MappingTarget TargetObject target);
}

@InheritInverseConfiguration

逆方向のマッピングに使用する設定を継承します
指定されたマッピングの逆のマッピング(ターゲットからソースへのマッピング)を自動的に生成します
⇒ 逆のマッピングを定義する手間を省くことができる

@Mapper
public interface MyMapper {
    @InheritInverseConfiguration
    SourceObject map(TargetObject target);
}

@BeforeMapping / @AfterMapping

マッピング前/後のカスタム処理を定義します
たとえば、変換前に特定のフィールドを設定したり、変換後に後処理を行ったりできます

@BeforeMapping

@Mapper
public interface MyMapper {
    @BeforeMapping
    default void beforeMapping(SourceObject source) {
        // マッピング前の処理
        source.setCreatedAt(LocalDateTime.now()); // 例: ソースオブジェクトの作成日時を設定
    }

    TargetObject map(SourceObject source);
}

※ マッピング処理の前にソースオブジェクトの更新日時を現在の日時に設定しています

@AfterMapping

@Mapper
public interface MyMapper {
    @AfterMapping
    default void afterMapping(SourceObject source, @MappingTarget TargetObject target) {
        // マッピング後の処理
        target.setUpdatedAt(LocalDateTime.now()); // 例: ターゲットオブジェクトの更新日時を設定
    }

    TargetObject map(SourceObject source);
}

※ マッピング処理の後にターゲットオブジェクトの更新日時を現在の日時に設定しています


@Named

マッピングのカスタムメソッドに名前を付けます
この名前を使用して、他のマッピングで再利用できます

@Mapper
public interface MyMapper {
    @Named("customMapping")
    TargetObject customMap(SourceObject source);
}

上記の場合、customMapメソッドに@Named(“customMapping”)アノテーションが付いています
この名前はこのカスタムマッピングメソッドに付けられた名前で、他のマッピングでこのカスタムマッピングメソッドを再利用する場合に、@Namedで指定した名前を使用します

例えば、別のマッピングで同じカスタムマッピングメソッドを使用する場合は、以下のようになります

@Mapper
public interface AnotherMapper {
    @Named("customMapping")
    TargetObject anotherCustomMap(SourceObject source);
}

同じ名前のカスタムマッピングメソッドを複数のマッピングで再利用することができます(共通化ですかね)


@ValueMapping

列挙型など、特定の値をマップするために使用されます
異なる値をマッピングする必要がある場合に役立ちます

@Mapper
public interface MyMapper {
    @ValueMapping(source = "HIGH", target = "H")
    @ValueMapping(source = "LOW", target = "L")
    TargetEnum map(SourceEnum source);
}

SourceEnumの”HIGH”はTargetEnuのHとして扱う的なイメージですね!


@Context

マッピングのコンテキスト情報を提供します
マッピングプロセスに関連する追加の情報を渡すために使用されます

public class MyCustomContext {
    private boolean advancedMapping;

    // コンストラクタ、getter、setterなど
}

@Mapper
public interface MyMapper {
    @Mapping(target = "someField", source = "sourceField")
    TargetObject map(SourceObject source, @Context MyCustomContext context);

    @Named("advancedMapping")
    @Mapping(target = "someField", source = "sourceField")
    TargetObject advancedMap(SourceObject source, @Context MyCustomContext context);
}

mapメソッドが呼び出されると、MyMapper内で定義されたマッピングメソッドがMyCustomContextオブジェクトのadvancedMappingフラグの値に基づいて選択されます
advancedMappingフラグがtrueの場合にはadvancedMapメソッドが呼び出され、それ以外の場合にはmapメソッドが呼び出されます

※ @Namedアノテーションを使用することで、マッピングの処理が条件分岐されるような形になります
  通常のmapメソッドとadvancedMapメソッドは同じ入力と出力を持っていますが、@Named(“advancedMapping”)アノテーションを使用することで、異なる処理が行われるようになります


@IterableMapping

リストやセットなどのコレクションの要素をマッピングします
要素ごとのマッピングを定義し、リストやセットなどのコレクションを変換します

@Mapper
public interface MyMapper {
    @IterableMapping(elementTargetType = TargetElement.class)
    List<TargetElement> map(List<SourceElement> source);
}

※ 異なるフィールド名を持つ場合には、適切なフィールドへのマッピングが行われません

是非フォローしてください

最新の情報をお伝えします