Guia para JMapper

Guia para JMapper

*1. Visão geral *

Neste tutorial, exploraremos JMapper -* uma estrutura de mapeamento rápida e fácil de usar. *

Discutiremos diferentes maneiras de configurar o JMapper, como executar conversões personalizadas, bem como o mapeamento relacional.

===* 2. Configuração do Maven *

Primeiro, precisamos adicionar a JMapper dependency ao nosso pom.xml:

<dependency>
    <groupId>com.googlecode.jmapper-framework</groupId>
    <artifactId>jmapper-core</artifactId>
    <version>1.6.0.1</version>
</dependency>

===* 3. Modelos de origem e destino *

Antes de chegarmos à configuração, vamos dar uma olhada nos beans simples que vamos usar neste tutorial.

Primeiro, aqui está o nosso bean de origem - um User básico:

public class User {
    private long id;
    private String email;
    private LocalDate birthDate;
}

E nosso bean de destino, _UserDto: _

public class UserDto {
    private long id;
    private String username;
}
*Usaremos a biblioteca para mapear atributos do nosso bean de origem _User_ para o nosso bean de destino _UserDto _.*

Existem três maneiras de configurar o JMapper: usando a API, anotações e configuração XML.

Nas seções a seguir, abordaremos cada uma delas.

*4. Usando a API *

Vamos ver como configurar o JMapper usando a API.

Aqui, não precisamos adicionar nenhuma configuração às nossas classes de origem e destino. Em vez disso, toda a* configuração pode ser feita usando _ JMapperAPI *, _, o que o torna o método de configuração mais flexível:

@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<UserDto, User> 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());
}

Aqui, usamos o método mappedClass () _ para definir nossa classe mapeada _UserDto. Em seguida, usamos o método _attribute () _ para definir cada atributo e seu valor mapeado.

Em seguida, criamos um objeto JMapper com base na configuração e usamos seu método getDestination () _ para obter o resultado _UserDto.

*5. Usando anotações *

Vamos ver como* podemos usar a anotação _ @ JMap_ para configurar nosso mapeamento *:

public class UserDto {
    @JMap
    private long id;

    @JMap("email")
    private String username;
}

E aqui está como usaremos nosso JMapper:

@Test
public void givenUser_whenUseAnnotation_thenConverted(){
    JMapper<UserDto, User> 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());
}

Observe que, para o atributo id, não precisamos fornecer um nome de campo de destino, pois é o mesmo nome do bean de origem, enquanto que para o campo username mencionamos que ele corresponde ao campo email na classe User.

Então, precisamos apenas passar os beans de origem e de destino para o nosso JMapper - nenhuma configuração adicional é necessária.

No geral, esse método é conveniente, pois utiliza a menor quantidade de código.

*6. Usando a configuração XML *

Também podemos usar a configuração XML para definir nosso mapeamento.

Aqui está nossa configuração XML de amostra em user_jmapper.xml:

<jmapper>
  <class name="com..jmapper.UserDto">
    <attribute name="id">
      <value name="id"/>
    </attribute>
    <attribute name="username">
      <value name="email"/>
    </attribute>
  </class>
</jmapper>

E precisamos passar nossa configuração XML para JMapper:

@Test
public void givenUser_whenUseXml_thenConverted(){
    JMapper<UserDto, User> 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());
}

Também podemos passar a configuração XML como String diretamente para JMapper em vez de um nome de arquivo.

===* 7. Mapeamento Global *

*Podemos tirar vantagem do mapeamento global se tivermos vários campos com o mesmo nome nos beans de origem e de destino.*

Por exemplo, se tivermos um UserDto1 que possui dois campos, id e email:

public class UserDto1 {
    private long id;
    private String email;

   //standard constructor, getters, setters
}

O mapeamento global será mais fácil de usar, pois eles são mapeados para campos com o mesmo nome no bean de origem User.

7.1 Usando a API

Para a configuração JMapperAPI, usaremos _global () _:

@Test
public void givenUser_whenUseApiGlobal_thenConverted() {
    JMapperAPI jmapperApi = new JMapperAPI()
      .add(mappedClass(UserDto.class).add(global())) ;
    JMapper<UserDto1, User> 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 Usando anotações

Para a configuração da anotação, usaremos _ @ JGlobalMap_ no nível da classe:

@JGlobalMap
public class UserDto1 {
    private long id;
    private String email;
}

E aqui está um teste simples:

@Test
public void whenUseGlobalMapAnnotation_thenConverted(){
    JMapper<UserDto1, User> 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. Configuração XML

E para a configuração XML, temos o elemento _ <global/> _:

<jmapper>
  <class name="com..jmapper.UserDto1">
    <global/>
  </class>
</jmapper>

E depois passe o nome do arquivo XML:

@Test
public void givenUser_whenUseXmlGlobal_thenConverted(){
    JMapper<UserDto1, User> 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. Conversões personalizadas *

Agora, vamos ver como aplicar uma conversão personalizada usando JMapper.

Temos um novo campo age em nosso UserDto, que precisamos calcular a partir do atributo User birthDate:

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();
    }
}

Portanto,* usamos _ @ JMapConversion_ para aplicar uma conversão complexa *do UserData de nascimento do usuário ao atributo _UserDto’s age. Portanto, o campo age será calculado quando mapearmos User para UserDto:

@Test
public void whenUseAnnotationExplicitConversion_thenConverted(){
    JMapper<UserDto, User> 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. Mapeamento relacional *

Por fim, discutiremos o mapeamento relacional.* Com esse método, precisamos definir nosso JMapper usando uma classe de destino a cada vez. *

Se já conhecemos as classes de destino, podemos defini-las para cada campo mapeado e usar RelationalJMapper.

Neste exemplo, temos um bean de origem User:

public class User {
    private long id;
    private String email;
}

E dois beans de destino UserDto1:

public class UserDto1 {
    private long id;
    private String username;
}

E UserDto2:

public class UserDto2 {
    private long id;
    private String email;
}

Vamos ver como tirar proveito do nosso RelationalJMapper.

====* 9.1 Usando a API *

Para nossa configuração de API, podemos definir classes de destino para cada atributo usando _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<User> 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());
}

Observe que, para cada classe de destino, precisamos definir o nome do atributo de destino.

O RelationalJMapper leva apenas uma classe - a classe mapeada.

====* 9.2. Usando anotações *

Para a abordagem de anotação, definiremos as classes também:

public class User {
    @JMap(classes = {UserDto1.class, UserDto2.class})
    private long id;

    @JMap(
      attributes = {"username", "email"},
      classes = {UserDto1.class, UserDto2.class})
    private String email;
}

Como de costume, nenhuma configuração adicional é necessária quando usamos anotações:

@Test
public void givenUser_whenUseAnnotation_thenConverted(){
    RelationalJMapper<User> 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 Configuração XML *

Para a configuração XML, usamos _ <classes> _ para definir as classes de destino para cada atributo.

Aqui está o nosso user_jmapper2.xml:

<jmapper>
  <class name="com..jmapper.relational.User">
    <attribute name="id">
      <value name="id"/>
      <classes>
        <class name="com..jmapper.relational.UserDto1"/>
        <class name="com..jmapper.relational.UserDto2"/>
      </classes>
    </attribute>
    <attribute name="email">
      <attributes>
        <attribute name="username"/>
        <attribute name="email"/>
      </attributes>
      <classes>
        <class name="com..jmapper.relational.UserDto1"/>
        <class name="com..jmapper.relational.UserDto2"/>
      </classes>
    </attribute>
  </class>
</jmapper>

E então passe o arquivo de configuração XML para RelationalJMapper:

@Test
public void givenUser_whenUseXml_thenConverted(){
    RelationalJMapper<User> 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. Conclusão*

Neste tutorial, aprendemos diferentes maneiras de configurar o JMapper e como executar uma conversão personalizada.

O código fonte completo dos exemplos pode ser encontrado em over no GitHub.