Руководство по JMapper
1. обзор
В этом руководстве мы рассмотримJMapper -a fast and easy to use mapping framework.
Мы обсудим различные способы настройки JMapper, как выполнять пользовательские преобразования, а также реляционное сопоставление.
2. Конфигурация Maven
Во-первых, нам нужно добавитьJMapper dependency к нашемуpom.xml:
com.googlecode.jmapper-framework
jmapper-core
1.6.0.1
3. Исходная и конечная модели
Прежде чем мы перейдем к настройке, давайте взглянем на простые bean-компоненты, которые мы собираемся использовать в этом руководстве.
Во-первых, вот наш исходный компонент - базовыйUser:
public class User {
private long id;
private String email;
private LocalDate birthDate;
}
И наш целевой компонент,UserDto:
public class UserDto {
private long id;
private String username;
}
Мы будем использовать библиотеку для сопоставления атрибутов исходного компонентаUser с целевым компонентомUserDto.
Существует три способа настройки JMapper: с помощью API, аннотаций и конфигурации XML.
В следующих разделах мы рассмотрим каждый из них.
4. Использование API
Давайте посмотрим, как настроитьJMapper с помощью API.
Здесь нам не нужно добавлять какую-либо конфигурацию к нашим исходным и целевым классам. Вместо этого всеthe configuration can be done using*JMapperAPI*,, что делает его наиболее гибким методом настройки:
@Test
public void givenUser_whenUseApi_thenConverted(){
JMapperAPI jmapperApi = new JMapperAPI()
.add(mappedClass(UserDto.class)
.add(attribute("id").value("id"))
.add(attribute("username").value("email")));
JMapper userMapper = new JMapper<>
(UserDto.class, User.class, jmapperApi);
User user = new User(1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getUsername());
}
Здесь мы используем методmappedClass(), чтобы определить наш сопоставленный классUserDto. Затем мы использовали методattribute(), чтобы определить каждый атрибут и его сопоставленное значение.
Затем мы создали объектJMapper на основе конфигурации и использовали его методgetDestination() для получения результатаUserDto.
5. Использование аннотаций
Посмотрим, какwe can use the @JMap annotation to configure our mapping:
public class UserDto {
@JMap
private long id;
@JMap("email")
private String username;
}
А вот как мы будем использовать нашJMapper:
@Test
public void givenUser_whenUseAnnotation_thenConverted(){
JMapper userMapper = new JMapper<>(UserDto.class, User.class);
User user = new User(1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getUsername());
}
Обратите внимание, что для атрибутаid нам не нужно указывать имя целевого поля, так как оно совпадает с именем исходного bean-компонента, а для поляusername мы упоминаем, что оно соответствуетemail в классеUser.
Затемwe only need to pass source and destination beans to our JMapper - дальнейшая настройка не требуется.
В целом, этот метод удобен, поскольку использует наименьшее количество кода.
6. Использование конфигурации XML
Мы также можем использовать конфигурацию XML для определения нашего отображения.
Вот наш пример конфигурации XML вuser_jmapper.xml:
И нам нужно передать нашу XML-конфигурацию вJMapper:
@Test
public void givenUser_whenUseXml_thenConverted(){
JMapper userMapper = new JMapper<>
(UserDto.class, User.class,"user_jmapper.xml");
User user = new User(1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getUsername());
}
Мы также можем передать конфигурацию XML какString непосредственно вJMapper вместо имени файла.
7. Глобальное картирование
Мы можем воспользоваться преимуществом глобального сопоставления, если у нас есть несколько полей с одинаковыми именами как в исходном, так и в целевом bean-компонентах.
Например, если у нас естьUserDto1 с двумя полями,id иemail:
public class UserDto1 {
private long id;
private String email;
// standard constructor, getters, setters
}
Глобальное сопоставление будет проще использовать, поскольку оно сопоставлено с полями с тем же именем в исходном компонентеUser.
7.1. Использование API
Для конфигурацииJMapperAPI мы будем использоватьglobal():
@Test
public void givenUser_whenUseApiGlobal_thenConverted() {
JMapperAPI jmapperApi = new JMapperAPI()
.add(mappedClass(UserDto.class).add(global())) ;
JMapper userMapper1 = new JMapper<>
(UserDto1.class, User.class,jmapperApi);
User user = new User(1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto1 result = userMapper1.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getEmail());
}
7.2. Использование аннотаций
Для конфигурации аннотации мы будем использовать@JGlobalMap на уровне класса:
@JGlobalMap
public class UserDto1 {
private long id;
private String email;
}
А вот простой тест:
@Test
public void whenUseGlobalMapAnnotation_thenConverted(){
JMapper userMapper= new JMapper<>(
UserDto1.class, User.class);
User user = new User(
1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto1 result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getEmail());
}
7.3. Конфигурация XML
А для конфигурации XML у нас есть элемент<global/>:
А затем передайте имя файла XML:
@Test
public void givenUser_whenUseXmlGlobal_thenConverted(){
JMapper userMapper = new JMapper<>
(UserDto1.class, User.class,"user_jmapper1.xml");
User user = new User(1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto1 result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getEmail());
}
8. Пользовательские преобразования
Теперь давайте посмотрим, как применить пользовательское преобразование с помощьюJMapper.
У нас есть новое полеage в нашемUserDto, которое нам нужно вычислить из атрибутаUserbirthDate:
public class UserDto {
@JMap
private long id;
@JMap("email")
private String username;
@JMap("birthDate")
private int age;
@JMapConversion(from={"birthDate"}, to={"age"})
public int conversion(LocalDate birthDate){
return Period.between(birthDate, LocalDate.now())
.getYears();
}
}
Итак,we used @JMapConversion to apply a complex conversion из атрибутаUser’s birthDate в атрибутUserDto’sage. Следовательно, полеage будет вычислено, когда мы сопоставимUser сUserDto:
@Test
public void whenUseAnnotationExplicitConversion_thenConverted(){
JMapper userMapper = new JMapper<>(
UserDto.class, User.class);
User user = new User(
1L,"[email protected]", LocalDate.of(1980,8,20));
UserDto result = userMapper.getDestination(user);
assertEquals(user.getId(), result.getId());
assertEquals(user.getEmail(), result.getUsername());
assertTrue(result.getAge() > 0);
}
9. Реляционное отображение
Наконец, мы обсудим реляционное отображение. With this method, we need to define our JMapper using a target class each time.с
Если мы уже знаем целевые классы, мы можем определить их для каждого отображаемого поля и использоватьRelationalJMapper.
В этом примере у нас есть один исходный компонентUser:
public class User {
private long id;
private String email;
}
И два целевых beansUserDto1:
public class UserDto1 {
private long id;
private String username;
}
ИUserDto2:
public class UserDto2 {
private long id;
private String email;
}
Давайте посмотрим, как воспользоваться нашимRelationalJMapper.
9.1. Использование API
Для нашей конфигурации API мы можем определить целевые классы для каждого атрибута, используяtargetClasses():
@Test
public void givenUser_whenUseApi_thenConverted(){
JMapperAPI jmapperApi = new JMapperAPI()
.add(mappedClass(User.class)
.add(attribute("id")
.value("id")
.targetClasses(UserDto1.class,UserDto2.class))
.add(attribute("email")
.targetAttributes("username","email")
.targetClasses(UserDto1.class,UserDto2.class)));
RelationalJMapper relationalMapper = new RelationalJMapper<>
(User.class,jmapperApi);
User user = new User(1L,"[email protected]");
UserDto1 result1 = relationalMapper
.oneToMany(UserDto1.class, user);
UserDto2 result2 = relationalMapper
.oneToMany(UserDto2.class, user);
assertEquals(user.getId(), result1.getId());
assertEquals(user.getEmail(), result1.getUsername());
assertEquals(user.getId(), result2.getId());
assertEquals(user.getEmail(), result2.getEmail());
}
Обратите внимание, что для каждого целевого класса нам нужно определить имя целевого атрибута.
RelationalJMapper принимает только один класс - сопоставленный класс.
9.2. Использование аннотаций
Для аннотационного подхода мы также определимclasses:
public class User {
@JMap(classes = {UserDto1.class, UserDto2.class})
private long id;
@JMap(
attributes = {"username", "email"},
classes = {UserDto1.class, UserDto2.class})
private String email;
}
Как обычно, при использовании аннотаций дополнительная настройка не требуется:
@Test
public void givenUser_whenUseAnnotation_thenConverted(){
RelationalJMapper relationalMapper
= new RelationalJMapper<>(User.class);
User user = new User(1L,"[email protected]");
UserDto1 result1 = relationalMapper
.oneToMany(UserDto1.class, user);
UserDto2 result2= relationalMapper
.oneToMany(UserDto2.class, user);
assertEquals(user.getId(), result1.getId());
assertEquals(user.getEmail(), result1.getUsername());
assertEquals(user.getId(), result2.getId());
assertEquals(user.getEmail(), result2.getEmail());
}
9.3. Конфигурация XML
Для конфигурации XML мы используем<classes> для определения целевых классов для каждого атрибута.
Вот нашuser_jmapper2.xml:
Затем передайте файл конфигурации XML вRelationalJMapper:
@Test
public void givenUser_whenUseXml_thenConverted(){
RelationalJMapper relationalMapper
= new RelationalJMapper<>(User.class,"user_jmapper2.xml");
User user = new User(1L,"[email protected]");
UserDto1 result1 = relationalMapper
.oneToMany(UserDto1.class, user);
UserDto2 result2 = relationalMapper
.oneToMany(UserDto2.class, user);
assertEquals(user.getId(), result1.getId());
assertEquals(user.getEmail(), result1.getUsername());
assertEquals(user.getId(), result2.getId());
assertEquals(user.getEmail(), result2.getEmail());
}
10. Заключение
В этом руководстве мы узнали о различных способах настройки JMapper и о том, как выполнять пользовательское преобразование.
Полный исходный код примеров можно найти вover on GitHub.