高速Mappingライブリ MapStructをLombokとJava11で使用する


MapStructとは

Entity(またはDomain)からDTOへの変換を助けてくれるライブラリです。
有名なMappingライブリとしては、Structs1.xのBeanUtilsや、ModelMapper・Dozerなどがあります。

MapStructの特徴は、Lombokと同じようにアノテーションプロセッサーを用いてコードを自動生成しているため、
ガリガリと自力でgetter/setterを用いてマッピングするのと同じぐらいに高速な点が特徴です。

性能については、下記記事で紹介されています。
Performance of Java Mapping Frameworks

主観となりますが、性能だけでなく、他のマッピングツールと比較しても、コードが直観的で解りやすいと感じています。

そんな素敵なMappingツールですが、ちょっと導入に色々と嵌ってしまった & 同様の記事が見つからなかったため、本記事を記載しています。

環境

Lombok Changelogによると1.8.2で、MapStructとのIntegrationについてのバグが修正されているようです

・Pleiades Eclipse 2018-09(※Lombok1.8.2)
・AdoptOpenJDK 11
・Lombok1.8.2
・MapStruct 1.2.0.Final および 1.3.0.Beta1

OKパータンの設定

結論としては、mapstruct-lombokのサンプルコードで稼働し、
MapStructのReadmeでは動作しませんでした(ドハマりしました)。

以下のようにpomを記載し、
eclipseでプロジェクトを選択し、実行 ⇒ maven install または maven testでコートが生成され、
mapstruct-lombokで記載されているテストコードが成功します。

残念ながら、eclipseの自動ビルドやクリーンによるビルドではコードが生成されません
IDE Supportは用意されており、「annotation processors」を自動で実行するように作られているのですが、
肝心の「annotation processors」をMavenに設定すると動かなくなるためです

pom.xml

    <properties>
        <org.mapstruct.version>1.3.0.Beta1</org.mapstruct.version> ※ 1.2.0.Finalも動作することを確認済み
        <org.projectlombok.version>1.18.2</org.projectlombok.version>
    </properties>
<!-- 省略 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId> ※Readmeとの差異になります
            <version>${org.mapstruct.version}</version>
            <scope>provided</scope> ※ コンパイル時に実行するように記載されています
        </dependency>
<!-- 省略 -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId> ※ ポイント Readmeで記載されているAnnotation-processorが記載されていない
                    <version>3.6.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

NGパターン代表例

pom.xml
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.6</source> <!-- or higher, depending on your project -->
                <target>1.6</target> <!-- or higher, depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId> ※ ← 少なくとも、Java11では動かないようです
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>

Java11の影響について

公式ドキュメントでは、using_mapstruct_on_java_9の項目で、「java.annotations.common」を有効化するように記載がされています。
その、java.annotations.commonがJava9で、java.xml.ws .annotation にリネームされていましたが、
なんと、Java11で、java.xml.ws.annotationが削除されています

今のところ、OKパターンのpom.xmlを記載し、mavenビルドを実行すれば、コードが生成され、
期待通り動くことは確認していますが、リスクがある可能性はご了承下さい

まとめ

本記事では、MapStructをlombokとJava11で使用する方法について記載しました。
実際のMapStructの使い方については、他のQiita記事や、本家のサンプルコードをご参考下さい。

ちょっと嵌るポイントもありますが、
自力でgetter/setterを記載して、バグを出す可能性を引くより、何百倍もコードを書くのが楽しくなります。

あなたのJavaライフにちょっと貢献出来たら幸いです。