Руководство по JMapper

Руководство по 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.