1. Обзор
В этом руководстве мы объясним, как сопоставлять списки различных типов элементов с помощью платформы ModelMapper . Это предполагает использование универсальных типов в Java в качестве решения для преобразования различных типов данных из одного списка в другой .
2. Сопоставитель модели
Основная роль ModelMapper заключается в сопоставлении объектов путем определения того, как одна объектная модель сопоставляется с другой, называемой объектом преобразования данных (DTO).
Чтобы использовать ModelMapper , мы начинаем с добавления зависимости в наш pom.xml
:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.7</version>
</dependency>
2.1. Конфигурация
ModelMapper предоставляет множество конфигураций для упрощения процесса сопоставления. Настраиваем конфигурацию, включая или отключая соответствующие свойства в конфигурации . Общепринятой практикой является установка для свойства fieldMatchingEnabled значения
true
и разрешение сопоставления частных полей :
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
Таким образом, ModelMapper может сравнивать частные поля в классах отображения (объектах). В этой конфигурации нет строгой необходимости, чтобы все поля с одинаковыми именами существовали в обоих классах. Допускается несколько стратегий сопоставления . По умолчанию стандартная стратегия сопоставления требует, чтобы все исходные и конечные свойства сопоставлялись в любом порядке. Это идеально подходит для нашего сценария .
2.2. Тип токена
ModelMapper использует TypeToken для сопоставления универсальных типов. Чтобы понять, почему это необходимо, давайте посмотрим, что происходит, когда мы сопоставляем список целых чисел
со списком символов
:
List<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(2);
integers.add(3);
List<Character> characters = new ArrayList<Character>();
modelMapper.map(integers, characters);
Далее, если мы распечатаем элементы списка символов
, мы увидим пустой список. Это происходит из-за возникновения стирания типа во время выполнения.
Если мы изменим наш вызов карты
, чтобы использовать TypeToken
, мы можем создать литерал типа для List<Character>
:
List<Character> characters
= modelMapper.map(integers, new TypeToken<List<Character>>() {}.getType());
Во время компиляции анонимный внутренний случай TokenType сохраняет тип параметра
List<Character>
, и на этот раз наше преобразование прошло успешно.
3. Использование пользовательского сопоставления типов
Списки в Java можно отображать с помощью пользовательских типов элементов.
Например, предположим, что мы хотим сопоставить список сущностей пользователя
со списком UserDTO
. Для этого мы будем вызывать map
для каждого элемента:
List<UserDTO> dtos = users
.stream()
.map(user -> modelMapper.map(user, UserDTO.class))
.collect(Collectors.toList());
Конечно, приложив немного усилий, мы могли бы создать параметризованный метод общего назначения:
<S, T> List<T> mapList(List<S> source, Class<T> targetClass) {
return source
.stream()
.map(element -> modelMapper.map(element, targetClass))
.collect(Collectors.toList());
}
Итак, вместо этого мы могли бы сделать :
List<UserDTO> userDtoList = mapList(users, UserDTO.class);
4. Карта типов и сопоставление свойств
В модель User-UserDTO
можно добавить определенные свойства, такие как списки или наборы . TypeMap
предоставляет метод для явного определения сопоставления этих свойств. Объект TypeMap
хранит информацию об отображении определенных типов (классов):
TypeMap<UserList, UserListDTO> typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class);
Класс UserList
содержит коллекцию User
s. Здесь мы хотим отобразить список имен пользователей из этой коллекции в список свойств класса UserListDTO
. Для этого мы создадим первый класс UsersListConverter
и передадим ему List <User>
и List <String>
в качестве типов параметров для преобразования:
public class UsersListConverter extends AbstractConverter<List<User>, List<String>> {
@Override
protected List<String> convert(List<User> users) {
return users
.stream()
.map(User::getUsername)
.collect(Collectors.toList());
}
}
Из созданного объекта TypeMap
мы явно добавляем сопоставление свойств , вызывая экземпляр класса UsersListConverter
:
typeMap.addMappings(mapper -> mapper.using(new UsersListConverter())
.map(UserList::getUsers, UserListDTO::setUsernames));
Внутри метода addMappings
сопоставление выражений позволяет нам определять свойства источника и назначения с помощью лямбда-выражений. Наконец, он преобразует список пользователей в результирующий список имен пользователей.
5. Вывод
В этом руководстве мы объяснили, как сопоставляются списки, манипулируя универсальными типами в ModelMapper .
Мы можем использовать TypeToken,
сопоставление универсальных типов и сопоставление свойств `` для создания типов списков объектов и выполнения сложных сопоставлений.
Полный исходный код этой статьи доступен на GitHub .