weblog

技術的なメモ置き場。

【MapStruct】Object Factory を使う

Object Factoryを使って、マッピングするオブジェクトを生成することができる。

環境

  • MapStruct : 1.2.0.Final
  • Java : 9
  • JUnit : 4.12
  • AssertJ : 3.9.1

Object Factoryの作成

public class StudentFactory {
    public Student createStudent() {
        Student student = new Student();
        student.setAddress("STUDENT_FACTORY");
        return student;
    }
}

Mapperの作成

@Mapper にFactoryクラスを指定する。

@Mapper(uses = StudentFactory.class)
public interface StudentMapper {

    StudentMapper MAPPER = Mappers.getMapper(StudentMapper.class);

    @Mapping(target = "address", ignore = true)
    Student toStudent(StudentEntity entity);
}

生成されたコード

/*
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2018-03-18T14:54:28+0900",
    comments = "version: 1.2.0.Final, compiler: javac, environment: Java 9.0.1 (Oracle Corporation)"
)
*/
public class StudentMapperImpl implements StudentMapper {

    private final StudentFactory studentFactory = new StudentFactory();

    @Override
    public Student toStudent(StudentEntity entity) {
        if ( entity == null ) {
            return null;
        }

        Student student = studentFactory.createStudent();

        student.setName( entity.getName() );
        student.setAge( entity.getAge() );

        return student;
    }
}

テストコード

@Test
public void test() {
    StudentEntity entity = new StudentEntity();
    Student student = StudentMapper.MAPPER.toStudent(entity);
    assertThat(student.getAddress()).isEqualTo("STUDENT_FACTORY");
}

【MapStruct】 Enum同士のマッピング

Enumを違う型のEnumに変換することができる。

環境

  • MapStruct : 1.2.0.Final
  • Java : 9
  • JUnit : 4.12
  • AssertJ : 3.9.1

Mapperの作成

@ValueMappingマッピングする識別子を指定する。

@Mapper
public interface SizeMapper {
    SizeMapper MAPPER = Mappers.getMapper(SizeMapper.class);

    @ValueMapping(source = "SMALL", target = "SHORT")
    @ValueMapping(source = "MEDIUM", target = "TALL")
    @ValueMapping(source = "LARGE", target = "GRANDE")
    SBSize toSBSize(Size size);
}

生成されたMapper

/*
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2018-03-17T22:54:45+0900",
    comments = "version: 1.2.0.Final, compiler: javac, environment: Java 9.0.1 (Oracle Corporation)"
)
*/
public class SizeMapperImpl implements SizeMapper {

    @Override
    public SBSize toSBSize(Size size) {
        if ( size == null ) {
            return null;
        }

        SBSize sBSize;

        switch ( size ) {
            case SMALL: sBSize = SBSize.SHORT;
            break;
            case MEDIUM: sBSize = SBSize.TALL;
            break;
            case LARGE: sBSize = SBSize.GRANDE;
            break;
            default: throw new IllegalArgumentException( "Unexpected enum constant: " + size );
        }

        return sBSize;
    }
}

テストコード

@Test
public void test1() {
    SBSize sbSize = SizeMapper.MAPPER.toSBSize(Size.SMALL);
    assertThat(sbSize).isEqualTo(SBSize.SHORT);
}

@Test
public void test2() {
    SBSize sbSize = SizeMapper.MAPPER.toSBSize(Size.LARGE);
    assertThat(sbSize).isEqualTo(SBSize.GRANDE);
}

MappingConstants を使うことでnullまたはデフォルト値を指定することもできる。

@ValueMapping(source = "VENTI", target = MappingConstants.NULL)
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "LARGE")
Size toSize(SBSize sbSize);

生成されたコード

@Override
public Size toSize(SBSize sbSize) {
    if ( sbSize == null ) {
        return null;
    }

    Size size;

    switch ( sbSize ) {
        case VENTI: size = null;
        break;
        default: size = Size.LARGE;
    }

    return size;
}

【MapStruct】 @Qualifierを使う

@Qualifier を使うことでアノテーションで独自の変換処理を追加することができる。

環境

  • MapStruct : 1.2.0.Final
  • Java : 9
  • JUnit : 4.12
  • AssertJ : 3.9.1

変換するクラスを用意する

public class Characters {

    public String upperCase(String string) {
        return (string == null) ? null : string.toUpperCase();
    }
}

アノテーションの作成

@Qualifier を合成したアノテーションを作成する。

@Qualifier
@Retention(CLASS)
@Target(TYPE)
public @interface CharacterConverter {
}
@Qualifier
@Retention(CLASS)
@Target(METHOD)
public @interface ToUpper {
}

アノテーションの付与

@CharacterConverter
public class Characters {

    @ToUpper
    public String upperCase(String string) {
        return (string == null) ? null : string.toUpperCase();
    }
}

Mapperの作成

nameを大文字にする。

@Mapper(uses = Characters.class)
public interface QualifierMapper {
    QualifierMapper MAPPER = Mappers.getMapper(QualifierMapper.class);

    @Mapping(target = "name", qualifiedBy = { CharacterConverter.class, ToUpper.class })
    Student toStudent(StudentEntity entity);
}

テストコード

@Test
public void test() {
    StudentEntity entity = new StudentEntity("curry", 30, "gsw");

    Student student = QualifierMapper.MAPPER.toStudent(entity);

    assertThat(student.getName()).isEqualTo("CURRY");
    assertThat(student.getAddress()).isEqualTo("gsw");
    assertThat(student.getAge()).isEqualTo(30);
}