Перейти к основному содержимому

Сопоставление списков с помощью ModelMapper

· 4 мин. чтения

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 .