【MapStruct】メソッドがマッピング対象のフィールドとなってしまうのを解決!?カスタム編
MapStructライブラリを使用してオブジェクト間のマッピングを行う際、特定のメソッドがフィールドとして認識され、コンパイル時にエラーが発生する場合の対処法はいくつかあります
その中で、「カスタムしたAccessorNamingStrategy」を使用して解決していきます!
ソースとデスティネーションのオブジェクトクラスを以下としますね
public class SourceObject {
private String someField;
// 通常のgetterとsetter
public String getSomeField() {
return someField;
}
public void setSomeField(String someField) {
this.someField = someField;
}
// MapStructに無視させたいメソッド
public String customMethod(String value) {
// メソッドの実装
return "processed: " + value;
}
}
public class DestinationObject {
private String someField;
public String getSomeField() {
return someField;
}
public void setSomeField(String someField) {
this.someField = someField;
}
}
1. カスタムAccessorNamingStrategyの実装
import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy;
import org.mapstruct.ap.spi.MapStructProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
public CustomAccessorNamingStrategy() {
super();
}
@Override
public boolean isGetterMethod(ExecutableElement method) {
// メソッド名が "customMethod" の場合はプロパティとして認識しない
if (method.getSimpleName().toString().equals("customMethod")) {
return false;
}
return super.isGetterMethod(method);
}
@Override
public boolean isSetterMethod(ExecutableElement method) {
// メソッド名が "customMethod" の場合はプロパティとして認識しない
if (method.getSimpleName().toString().equals("customMethod")) {
return false;
}
return super.isSetterMethod(method);
}
// カスタムメソッドを無視するための追加ロジック
@Override
public boolean isFluentSetterMethod(ExecutableElement method) {
// メソッド名が "customMethod" の場合はプロパティとして認識しない
if (method.getSimpleName().toString().equals("customMethod")) {
return false;
}
return super.isFluentSetterMethod(method);
}
}
「DefaultAccessorNamingStrategy」の「isGetterMethod」および「isSetterMethod」メソッドは、JavaBeans規約に基づいてgetterおよびsetterメソッドを特定しますが、戻り値があり引数を1つ持つメソッドは通常のgetterやsetterのパターンに当てはまらないため、通常は対象外となります
ただし、カスタムAccessorNamingStrategyを作成することで、これらのメソッドを特定し、無視することができます
以下に、戻り値があり引数を1つ持つメソッドを無視するためのカスタムAccessorNamingStrategyの例が上記となります
2. @MapperConfigでカスタム設定を使用
import org.mapstruct.MapperConfig;
@MapperConfig(
uses = CustomAccessorNamingStrategy.class
)
public interface CustomAccessorTypeConfig {
}
3. Mapperインターフェースにカスタム設定を適用
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper(config = CustomAccessorTypeConfig.class)
public interface YourMapper {
YourMapper INSTANCE = Mappers.getMapper(YourMapper.class);
DestinationObject toDestinationObject(SourceObject source);
}
4. build.gradleの設定はこんな感じ
plugins {
id 'java'
id 'eclipse' // Optional: for Eclipse integration
id 'idea' // Optional: for IntelliJ IDEA integration
}
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.mapstruct:mapstruct:1.5.5.Final' // 最新バージョンを指定してください
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
compileOnly 'org.projectlombok:lombok:1.18.24' // Optional: if you're using Lombok
annotationProcessor 'org.projectlombok:lombok:1.18.24' // Optional: if you're using Lombok
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
tasks.withType(JavaCompile) {
options.annotationProcessorPath = configurations.annotationProcessor
options.compilerArgs << "-Amapstruct.defaultComponentModel=spring" // Optional: if you're using Spring
}
このカスタムAccessorNamingStrategyを使用することで、customMethodがgetterやsetterとして認識されることを防ぎます
MapStructはこのメソッドを無視し、マッピングの対象としないようになります
是非参考にしていてください!
マッピング設定をあらかじめ用意しるのもよいですね
import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping;
@MapperConfig
public interface CustomMapperConfig {
@Mapping(target = "ignoredField", ignore = true)
void applyIgnoreIgnoredField(SourceObject source, @MappingTarget DestinationObject target);
}
下のmapperに適用してあげる
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
@Mapper(config = CustomMapperConfig.class)
public interface YourMapper {
YourMapper INSTANCE = Mappers.getMapper(YourMapper.class);
DestinationObject toDestinationObject(SourceObject source);
default void map(SourceObject source, @MappingTarget DestinationObject target) {
// applyIgnoreIgnoredFieldを呼び出して特定のフィールドを無視する
applyIgnoreIgnoredField(source, target);
}
void applyIgnoreIgnoredField(SourceObject source, @MappingTarget DestinationObject target);
}
是非フォローしてください
最新の情報をお伝えします