背景
親愛なる友人、読者の皆さん、こんにちは!記事を書く前に、少し背景を説明します...最近、
Mapstructライブラリの使用中に問題が発生しました。これについては、私のテレグラム チャネルで簡単に説明しまし
た。投稿の問題はコメントで解決されました。前のプロジェクトの同僚がこれに協力してくれました。
その後、このトピックについて記事を書くことにしましたが、もちろん狭い視野で見るのではなく、まずは Mapstruct とは何か、そしてなぜそれが必要なのかを理解し、実際の例を使用して理解していきます。以前に発生した状況を分析し、それを解決する方法。したがって、実際にすべてを体験するために、記事を読みながらすべての計算を並行して行うことを強くお勧めします。
始める前に、私の電報チャンネルを購読し、そこで自分の活動を収集し、Java と IT の開発全般についての考えを書きます。 購読しましたか? 素晴らしい!さて、それでは行きましょう!
Mapstruct、よくある質問?
高速なタイプセーフ Bean マッピングのためのコード ジェネレーター。 最初のタスクは、Mapstruct とは何か、そしてなぜそれが必要なのかを理解することです。一般的には、公式ウェブサイトでそれについて読むことができます。サイトのメイン ページには、質問に対する 3 つの答えがあります。それは何ですか? 何のために?どうやって?これもやってみます:
それは何ですか?
Mapstruct は、インターフェイスを通じて記述された構成に基づいて生成されたコードを使用して、一部のエンティティのオブジェクトを他のエンティティのオブジェクトにマッピング (一般に、マップ、マップ、マップなどと言う) するのに役立つライブラリです。
何のために?
ほとんどの場合、私たちはマルチレイヤー アプリケーション (データベースを操作するレイヤー、ビジネス ロジックのレイヤー、アプリケーションと外界との対話用のレイヤー) を開発し、各レイヤーにはデータを保存および処理するための独自のオブジェクトがあります。 。そして、このデータは、あるエンティティから別のエンティティに転送することによって、レイヤからレイヤに転送する必要があります。このアプローチを使ったことがない人にとっては、これは少し複雑に見えるかもしれません。たとえば、Student データベースのエンティティがあります。このエンティティのデータがビジネス ロジック (サービス) 層に送られるとき、データを Student クラスから StudentModel クラスに転送する必要があります。次に、ビジネス ロジックですべての操作を行った後、データを外部に解放する必要があります。このために StudentDto クラスがあります。もちろん、StudentModel クラスから StudentDto にデータを渡す必要があります。転送されるメソッドを毎回手書きするのは労力がかかります。さらに、これはコード ベース内の保守が必要な追加コードです。間違いを犯す可能性があります。そして、Mapstruct はコンパイル段階でそのようなメソッドを生成し、生成されたソースに保存します。
どうやって?
注釈の使用。必要なのは、このインターフェイスのメソッドを使用してあるオブジェクトから別のオブジェクトに変換できることをライブラリに伝えるメインの Mapper アノテーションを持つアノテーションを作成することだけです。学生について先ほど述べたように、私たちの場合、これは StudentMapper インターフェイスになります。これには、ある層から別の層にデータを転送するためのメソッドがいくつかあります。
public class Student {
private Long id;
private String firstName;
private String lastName;
private Integer age;
}
public class StudentDTO {
private Long id;
private String firstName;
private String lastName;
private Integer age;
}
public class StudentModel {
private Long id;
private String firstName;
private String lastName;
private Integer age;
}
これらのクラスに対して、マッパーを作成します (以下、これをインターフェースと呼びます。これは、何をどこに転送するかを記述します)。
@Mapper
public interface StudentMapper {
StudentModel toModel(StudentDTO dto);
Student toEntity(StudentModel model);
StudentModel toModel(Student entity);
StudentDTO toDto(StudentModel model);
}
このアプローチの利点は、フィールドの名前と型が異なるクラスで同じである場合 (今回の場合のように)、Mapstruct の設定だけで、コンパイル段階で StudentMapper インターフェイスに基づいて必要な実装を生成できることです。翻訳します。ということは、もう明らかになってきていますよね?さらに進んで、実際の例を使用して Spring Boot アプリケーションの作業を分析してみましょう。
Spring Boot と Mapstruct の動作例
最初に必要なのは、Spring Boot プロジェクトを作成し、それに Mapstruct を追加することです。この点に関して、私は
GitHub にリポジトリ用のテンプレートを備えた組織を持っており、Spring Boot の開始もその 1 つです。これに基づいて、新しいプロジェクトを作成します。 次に、
projectを取得します。
そうです、皆さん、このプロジェクトが役に立ったと思ったら、このプロジェクトに星を付けてください。そうすれば、私がこれをやっていることは無駄ではないことがわかります。 このプロジェクトでは、私が職場で受けた状況を明らかにし、
私の Telegram チャンネルへの投稿で説明します。知識のない人のために状況を簡単に説明します。マッパー (つまり、前に説明したインターフェイス実装) のテストを作成するとき、テストはできるだけ早く合格する必要があります。マッパーを使用する最も簡単なオプションは、テストの実行時に SpringBootTest アノテーションを使用することです。これにより、Spring Boot アプリケーションの ApplicationContext 全体が取得され、テスト内にテストに必要なマッパーが挿入されます。ただし、このオプションはリソースを大量に消費し、さらに時間がかかるため、私たちには適していません。単純に目的のマッパーを作成し、そのメソッドが期待どおりに動作することを確認する単体テストを作成する必要があります。テストを高速に実行する必要があるのはなぜですか? テストに時間がかかると、開発プロセス全体の速度が低下します。新しいコードがテストに合格するまで、このコードは正しいとは見なされず、テストには使用されません。つまり、コードは運用環境に導入されず、開発者が作業を完了していないことを意味します。動作が疑問の余地のないライブラリのテストをなぜ作成する必要があるのでしょうか? それでも、マッパーをどの程度正確に記述したか、そしてマッパーが期待どおりに動作するかどうかをテストしているため、テストを作成する必要があります。まず、作業を簡単にするために、pom.xml に別の依存関係を追加して、Lombok をプロジェクトに追加しましょう。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
私たちのプロジェクトでは、モデル クラス (ビジネス ロジックの操作に使用される) から、外部との通信に使用される DTO クラスに移行する必要があります。簡略化したバージョンでは、フィールドは変更されず、マッパーは単純であると想定します。ただし、ご希望があれば、Mapstruct の操作方法、構成方法、およびその利点の活用方法について、より詳細な記事を書くことも可能です。ただし、この記事はかなり長くなるので。出席する講義と講師のリストを持っている学生がいるとします。
モデルパッケージを作成しましょう。これに基づいて、単純なモデルを作成します。
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
import java.util.List;
@Data
public class StudentDTO {
private Long id;
private String name;
private List<LectureDTO> lectures;
private List<LecturerDTO> lecturers;
}
彼の講義
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
@Data
public class LectureDTO {
private Long id;
private String name;
}
と講師
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
@Data
public class LecturerDTO {
private Long id;
private String name;
}
そして、
modelパッケージの隣に
dtoパッケージを作成します。
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
import java.util.List;
@Data
public class StudentDTO {
private Long id;
private String name;
private List<LectureDTO> lectures;
private List<LecturerDTO> lecturers;
}
講義
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
@Data
public class LectureDTO {
private Long id;
private String name;
}
と講師
package com.github.romankh3.templaterepository.springboot.dto;
import lombok.Data;
@Data
public class LecturerDTO {
private Long id;
private String name;
}
次に、講義モデルのコレクションを DTO 講義のコレクションに変換するマッパーを作成しましょう。最初に行うことは、Mapstruct をプロジェクトに追加することです。
これを行うには、公式ウェブサイトを使用します。そこにはすべてが説明されています。つまり、1 つの依存関係とプラグインをメモリに追加する必要があります (メモリとは何かについて質問がある場合は、
Article1と
Article2を参照してください)。
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<build/> ブロックのメモリ内にあります。それはまだありません:
<build>
<plugins>
<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-processor</artifactId>
<version>1.4.2.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
次に、 dtoと
modelの隣に
マッパーパッケージ を作成しましょう。前に示したクラスに基づいて、さらに 5 つのマッパーを作成する必要があります。
- Mapper レクチャーモデル <-> レクチャー DTO
- マッパー リスト<LectureModel> <-> リスト<LectureDTO>
- マッパー講師モデル <-> 講師DTO
- マッパー リスト<講師モデル> <-> リスト<講師DTO>
- マッパー StudentModel <-> StudentDTO
行く:
レクチャーマッパー
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;
@Mapper(componentModel = "spring")
public interface LectureMapper {
LectureDTO toDTO(LectureModel model);
LectureModel toModel(LecturerDTO dto);
}
レクチャーリストマッパー
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring", uses = LectureMapper.class)
public interface LectureListMapper {
List<LectureModel> toModelList(List<LectureDTO> dtos);
List<LectureDTO> toDTOList(List<LectureModel> models);
}
講師マッパー
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;
@Mapper(componentModel = "spring")
public interface LectureMapper {
LectureDTO toDTO(LectureModel model);
LectureModel toModel(LectureDTO dto);
}
講師リストマッパー
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LecturerModel;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring", uses = LecturerMapper.class)
public interface LecturerListMapper {
List<LecturerModel> toModelList(List<LecturerDTO> dloList);
List<LecturerDTO> toDTOList(List<LecturerModel> modelList);
}
StudentMapper
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.StudentDTO;
import com.github.romankh3.templaterepository.springboot.model.StudentModel;
import org.mapstruct.Mapper;
@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
public interface StudentMapper {
StudentDTO toDTO(StudentModel model);
StudentModel toModel(StudentDTO dto);
}
マッパーでは他のマッパーを参照することに別途注意してください。これは、 StudentMapper で行われるのと同様に、Mapper アノテーションの
usesフィールドを通じて行われます。
@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
ここでは 2 つのマッパーを使用して、講義のリストと講師のリストを正しくマッピングします。次に、コードをコンパイルして、そこに何がどのように存在するかを確認する必要があります。
これは、 mvn clean COMPILEコマンドを使用して行うことができます。しかし、結局のところ、マッパーの Mapstruct 実装を作成するときに、マッパー実装はフィールドを上書きしませんでした。なぜ?Lombok から Data アノテーションを取得できないことが判明しました。そして、何かをしなければなりませんでした... したがって、記事に新しいセクションがあります。
Lombok と Mapstruct のリンク
数分間検索した結果、Lombok と Mapstruct を特定の方法で接続する必要があることが判明しました。
これに関する情報は、 Mapstruct のドキュメントにあります。Mapstruct の開発者によって提案された例を調べた後、pom.xml を更新しましょう。個別のバージョンを追加しましょう。
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
不足している依存関係を追加しましょう。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</dependency>
そして、Lombok と Mapstruct を接続できるようにコンパイラー プラグインを更新しましょう。
<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-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
この後はすべてうまくいくはずです。プロジェクトを再度コンパイルしましょう。しかし、Mapstruct が生成したクラスはどこで見つけられるのでしょうか? これらは生成されたソースにあります:
${projectDir}/target/generated-sources/annotations/ これで、Mapstruct の投稿からの失望を理解する準備ができたので、マッパー用のテストを作成してみましょう。
マッパー用のテストを作成します
統合テストを作成し、その完了時間を気にしない場合に、マッパーの 1 つをテストする簡単なテストを作成します。
レクチャーマッパーテスト
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class LectureMapperTest {
@Autowired
private LectureMapper mapperUnderTest;
@Test
void shouldProperlyMapModelToDto() {
LectureModel model = new LectureModel();
model.setId(11L);
model.setName("lecture name");
LectureDTO dto = mapperUnderTest.toDTO(model);
Assertions.assertNotNull(dto);
Assertions.assertEquals(model.getId(), dto.getId());
Assertions.assertEquals(model.getName(), dto.getName());
}
@Test
void shouldProperlyMapDtoToModel() {
LectureDTO dto = new LectureDTO();
dto.setId(11L);
dto.setName("lecture name");
LectureModel model = mapperUnderTest.toModel(dto);
Assertions.assertNotNull(model);
Assertions.assertEquals(dto.getId(), model.getId());
Assertions.assertEquals(dto.getName(), model.getName());
}
}
ここでは、SpringBootTest アノテーションを使用して applicationContext 全体を起動し、そこから Autowired アノテーションを使用してテストに必要なクラスを抽出します。テストの作成速度と容易さの観点から、これは非常に優れています。テストは正常に成功し、すべて問題ありません。しかし、ここでは逆に、LectureListMapper などのマッパーの単体テストを作成します。
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.List;
class LectureListMapperTest {
private final LectureListMapper lectureListMapper = new LectureListMapperImpl();
@Test
void shouldProperlyMapListDtosToListModels() {
LectureDTO dto = new LectureDTO();
dto.setId(12L);
dto.setName("I'm BATMAN!");
List<LectureDTO> dtos = Collections.singletonList(dto);
List<LectureModel> models = lectureListMapper.toModelList(dtos);
Assertions.assertNotNull(models);
Assertions.assertEquals(1, models.size());
Assertions.assertEquals(dto.getId(), models.get(0).getId());
Assertions.assertEquals(dto.getName(), models.get(0).getName());
}
}
Mapstruct が生成する実装はプロジェクトと同じクラスにあるため、テストで簡単に使用できます。すべてが素晴らしく見えます。注釈は必要ありません。最も単純な方法で必要なクラスを作成するだけです。しかし、テストを実行すると、テストがクラッシュし、コンソールに NullPointerException が表示されることがわかります。これは、LectureListMapper マッパーの実装が次のようになっているためです。
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2021-12-09T21:46:12+0300",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {
@Autowired
private LectureMapper lectureMapper;
@Override
public List<LectureModel> toModelList(List<LectureDTO> dtos) {
if ( dtos == null ) {
return null;
}
List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
for ( LectureDTO lectureDTO : dtos ) {
list.add( lectureMapper.toModel( lectureDTO ) );
}
return list;
}
@Override
public List<LectureDTO> toDTOList(List<LectureModel> models) {
if ( models == null ) {
return null;
}
List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
for ( LectureModel lectureModel : models ) {
list.add( lectureMapper.toDTO( lectureModel ) );
}
return list;
}
}
NPE (NullPointerException の略) を見ると、
lectureMapper変数から取得されていますが、初期化されていないことがわかります。しかし、私たちの実装には、変数を初期化できるコンストラクターがありません。これがまさに、Mapstruct がこの方法でマッパーを実装した理由です。Spring では、いくつかの方法で Bean をクラスに追加できます。上で行ったように Autowired アノテーションとともにフィールドを通じてビーンを注入したり、コンストラクターを通じてビーンを注入したりできます。仕事でテストの実行時間を最適化する必要があるときに、このような問題のある状況に陥ったことに気づきました。私はこれについては何もできないと思い、自分の痛みを Telegram チャンネルに吐き出しました。そして、彼らはコメントで私を助け、注入戦略をカスタマイズすることが可能であると言いました。Mapper インターフェイスには、
injectionStrategy field があり、
FIELDと
CONSTRUCTORという 2 つの値を持つ
InjectionStrategy name を受け入れるだけです。
これを理解した上で、この設定をマッパーに追加しましょう。例として、 LectureListMapperを使用して示します。
@Mapper(componentModel = "spring", uses = LectureMapper.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface LectureListMapper {
List<LectureModel> toModelList(List<LectureDTO> dtos);
List<LectureDTO> toDTOList(List<LectureModel> models);
}
追加した部分を太字で強調しました。他のすべてのオプションにこのオプションを追加し、マッパーが新しい行で生成されるようにプロジェクトを再コンパイルしましょう。
これを行うと、 LectureListMapperのマッパーの実装がどのように変更されたかを見てみましょう(必要な部分を太字で強調表示しています)。
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2021-12-09T22:25:37+0300",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {
private final LectureMapper lectureMapper;
@Autowired
public LectureListMapperImpl(LectureMapper lectureMapper) {
this.lectureMapper = lectureMapper;
}
@Override
public List<LectureModel> toModelList(List<LectureDTO> dtos) {
if ( dtos == null ) {
return null;
}
List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
for ( LectureDTO lectureDTO : dtos ) {
list.add( lectureMapper.toModel( lectureDTO ) );
}
return list;
}
@Override
public List<LectureDTO> toDTOList(List<LectureModel> models) {
if ( models == null ) {
return null;
}
List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
for ( LectureModel lectureModel : models ) {
list.add( lectureMapper.toDTO( lectureModel ) );
}
return list;
}
}
そして現在、Mapstruct はコンストラクターを介してマッパー インジェクションを実装しています。これはまさに私たちが達成しようとしていたことです。これでテストはコンパイルを停止します。テストを更新して以下を取得しましょう。
package com.github.romankh3.templaterepository.springboot.mapper;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.List;
class LectureListMapperTest {
private final LectureListMapper lectureListMapper = new LectureListMapperImpl(new LectureMapperImpl());
@Test
void shouldProperlyMapListDtosToListModels() {
LectureDTO dto = new LectureDTO();
dto.setId(12L);
dto.setName("I'm BATMAN!");
List<LectureDTO> dtos = Collections.singletonList(dto);
List<LectureModel> models = lectureListMapper.toModelList(dtos);
Assertions.assertNotNull(models);
Assertions.assertEquals(1, models.size());
Assertions.assertEquals(dto.getId(), models.get(0).getId());
Assertions.assertEquals(dto.getName(), models.get(0).getName());
}
}
さて、テストを実行すると、LectureListMapperImpl で必要なLectureMapperを渡しているため、すべてが期待どおりに動作します... 勝利です! あなたにとっては難しいことではありませんが、私は嬉しく思います。
皆さん、すべていつも通りです。私のGitHub アカウント、私のTelegram アカウントを購読してください。そこでは私の活動の結果を投稿します。本当に役立つものがあります)特に電報チャンネルのディスカッショングループに参加することをお勧めします。誰かが技術的な質問をした場合、そこで答えを得ることができることがあります。この形式は誰にとっても興味深いもので、誰が何を知っているかを読んで経験を積むことができます。
結論
この記事の一環として、Mapstruct のような必要かつ頻繁に使用される製品について知りました。私たちはそれが何なのか、なぜ、どのようにして起こるのかを理解しました。実際の例を使って、何ができるのか、どう変えられるのかを感じました。また、マッパーを適切にテストできるように、コンストラクターを介して Bean の注入を設定する方法も検討しました。Mapstruct の同僚は、彼らの製品のユーザーがマッパーを注入する方法を正確に選択できるようにしてくれました。私たちは間違いなく彼らに感謝しています。しかし、Spring ではコンストラクターを介して Bean を注入することを推奨しているにもかかわらず、Mapstruct の開発者はデフォルトでフィールドを介した注入を設定しています。何故ですか?答えはありません。おそらく私たちが知らない理由があり、それが彼らがこのようにしたのではないかと思います。そして、彼らから情報を得るために、私は彼らの公式製品リポジトリに
GitHub の問題を作成しました。
GO TO FULL VERSION