«1. Обзор
В этой статье мы узнаем, как использовать пользовательский преобразователь с библиотекой MapStruct.
Библиотека MapStruct используется для отображения между типами компонентов Java. Используя пользовательский сопоставитель с MapStruct, мы можем настроить методы сопоставления по умолчанию.
2. Зависимости Maven
Давайте добавим библиотеку mapstruct в наш Maven pom.xml:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.3.1.Final</version>
</dependency>
Чтобы увидеть автоматически сгенерированные методы внутри целевой папки проекта, мы должны добавить annotationProcessorPaths к подключаемому модулю maven-compiler-plugin:
<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</artifactId>
<version>1.3.1.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
3. Пользовательский преобразователь
Пользовательские преобразователи используются для выполнения конкретных требований преобразования. Чтобы достичь этого, мы должны определить метод для преобразования. Затем мы должны уведомить MapStruct о методе. Наконец, MapStruct вызовет метод для преобразования исходного объекта в целевой.
Например, давайте представим, что у нас есть приложение, которое вычисляет отчет об индексе массы тела (ИМТ) пользователя. Чтобы рассчитать ИМТ, мы должны собрать значения тела пользователя. Чтобы преобразовать имперские единицы в метрические, мы можем использовать пользовательские методы сопоставления.
Есть два способа использования пользовательского картографа с MapStruct. Мы можем либо вызвать пользовательский метод, введя его в свойствеqualifiedByName аннотации @Mapping, либо создать для него аннотацию.
Прежде чем мы начнем, мы должны определить класс DTO для хранения имперских значений:
public class UserBodyImperialValuesDTO {
private int inch;
private int pound;
// constructor, getters, and setters
}
Далее давайте определим класс DTO для хранения значений метрик:
public class UserBodyValues {
private double kilogram;
private double centimeter;
// constructor, getters, and setters
}
3.1. Пользовательский преобразователь с методом
Чтобы начать использовать собственные преобразователи, давайте создадим интерфейс с аннотацией @Mapper:
@Mapper
public interface UserBodyValuesMapper {
//...
}
Во-вторых, давайте создадим наш собственный метод с типом возвращаемого значения, который мы хотим, и аргументом, который нам нужно преобразовать. Мы должны использовать аннотацию @Named с параметром value, чтобы сообщить MapStruct о пользовательском методе сопоставления:
@Mapper
public interface UserBodyValuesMapper {
@Named("inchToCentimeter")
public static double inchToCentimeter(int inch) {
return inch * 2.54;
}
//...
}
И, наконец, давайте определим метод интерфейса сопоставления с помощью аннотации @Mapping. В этой аннотации мы сообщим MapStruct о типе источника, типе цели и методе, который он будет использовать:
@Mapper
public interface UserBodyValuesMapper {
UserBodyValuesMapper INSTANCE = Mappers.getMapper(UserBodyValuesMapper.class);
@Mapping(source = "inch", target = "centimeter", qualifiedByName = "inchToCentimeter")
public UserBodyValues userBodyValuesMapper(UserBodyImperialValuesDTO dto);
@Named("inchToCentimeter")
public static double inchToCentimeter(int inch) {
return inch * 2.54;
}
}
Давайте протестируем наш пользовательский преобразователь:
UserBodyImperialValuesDTO dto = new UserBodyImperialValuesDTO();
dto.setInch(10);
UserBodyValues obj = UserBodyValuesMapper.INSTANCE.userBodyValuesMapper(dto);
assertNotNull(obj);
assertEquals(25.4, obj.getCentimeter(), 0);
3.2. Пользовательский преобразователь с аннотацией
Чтобы использовать собственный преобразователь с аннотацией, мы должны определить аннотацию вместо аннотации @Named. Затем мы должны проинформировать MapStruct о вновь созданной аннотации, указав параметр квалифицированногоByName аннотации @Mapping.
Давайте посмотрим, как мы определяем аннотацию:
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PoundToKilogramMapper {
}
Давайте добавим аннотацию @PoundToKilogramMapper к нашему методу poundToKilogram:
@PoundToKilogramMapper
public static double poundToKilogram(int pound) {
return pound * 0.4535;
}
Теперь давайте определим метод интерфейса сопоставления с аннотацией @Mapping. В аннотации сопоставления мы сообщаем MapStruct о типе источника, целевом типе и классе аннотации, который он будет использовать:
@Mapper
public interface UserBodyValuesMapper {
UserBodyValuesMapper INSTANCE = Mappers.getMapper(UserBodyValuesMapper.class);
@Mapping(source = "pound", target = "kilogram", qualifiedBy = PoundToKilogramMapper.class)
public UserBodyValues userBodyValuesMapper(UserBodyImperialValuesDTO dto);
@PoundToKilogramMapper
public static double poundToKilogram(int pound) {
return pound * 0.4535;
}
}
Наконец, давайте протестируем наш пользовательский преобразователь:
UserBodyImperialValuesDTO dto = new UserBodyImperialValuesDTO();
dto.setPound(100);
UserBodyValues obj = UserBodyValuesMapper.INSTANCE.userBodyValuesMapper(dto);
assertNotNull(obj);
assertEquals(45.35, obj.getKilogram(), 0);
4. Заключение
В этой статье мы узнали, как использовать пользовательский преобразователь с библиотекой MapStruct.
Реализации этих примеров и тестов доступны на GitHub.