Guide to JMapper – JMapper指南

最后修改: 2018年 7月 21日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll explore JMapper – a fast and easy to use mapping framework.

在本教程中,我们将探讨JMapper一个快速且易于使用的映射框架。

We’ll discuss different ways to configure JMapper, how to perform custom conversions, as well as relational mapping.

我们将讨论配置JMapper的不同方法,如何执行自定义转换,以及关系映射。

2. Maven Configuration

2.Maven配置

First, we need to add the JMapper dependency to our pom.xml:

首先,我们需要将JMapper依赖性添加到我们的pom.xml

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

3. Source and Destination Models

3.源模式和目的模式

Before we get to the configuration, let’s take a look at the simple beans we’re going to use throughout this tutorial.

在我们进行配置之前,让我们看看我们在本教程中要使用的简单Bean。

First, here’s our source bean – a basic User:

首先,这是我们的源Bean–一个基本的User

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

And our destination bean, UserDto:

而我们的目标Bean,UserDto:

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

We’ll use the library to map attributes from our source bean User to our destination bean UserDto.

我们将使用该库将属性从源Bean User映射到目标Bean UserDto

There are three ways to configure JMapper: by using the API, annotations and XML configuration.

有三种方式来配置JMapper:通过使用API、注解和XML配置。

In the following sections, we’ll go over each of these.

在下面的章节中,我们将逐一介绍这些内容。

4. Using the API

4.使用API

Let’s see how to configure JMapper using the API.

让我们看看如何使用API配置JMapper

Here, we don’t need to add any configuration to our source and destination classes. Instead, all the configuration can be done using JMapperAPI, which makes it the most flexible configuration method:

在这里,我们不需要向我们的源和目标类添加任何配置。相反,所有的配置都可以使用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<UserDto, User> userMapper = new JMapper<>
      (UserDto.class, User.class, jmapperApi);
    User user = new User(1L,"john@test.com", LocalDate.of(1980,8,20));
    UserDto result = userMapper.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getUsername());
}

Here, we use the mappedClass() method to define our mapped class UserDto. Then, we used the attribute() method to define each attribute and its mapped value.

这里,我们使用mappedClass()方法来定义我们的映射类UserDto.,然后,我们使用attribute()方法来定义每个属性及其映射值。

Next, we created a JMapper object based on the configuration and used its getDestination() method to obtain the UserDto result.

接下来,我们根据配置创建了一个JMapper对象,并使用其getDestination()方法来获取UserDto结果。

5. Using Annotations

5.使用注解

Let’s see how we can use the @JMap annotation to configure our mapping:

让我们看看我们如何使用@JMap注解来配置我们的映射

public class UserDto {  
    @JMap
    private long id;

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

And here’s how we’ll use our JMapper:

下面是我们将如何使用我们的JMapper

@Test
public void givenUser_whenUseAnnotation_thenConverted(){
    JMapper<UserDto, User> userMapper = new JMapper<>(UserDto.class, User.class);
    User user = new User(1L,"john@test.com", LocalDate.of(1980,8,20));
    UserDto result = userMapper.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getUsername());        
}

Note that for the id attribute, we didn’t need to provide a target field name as it’s the same name as the source bean, while for the username field we mention that it corresponds to the email field in the User class.

请注意,对于id属性,我们不需要提供目标字段名,因为它与源Bean的名字相同,而对于username字段,我们提到它与User类中的email字段对应。

Then, we only need to pass source and destination beans to our JMapper – no further configuration needed.

然后,我们只需要将源Bean和目的Bean传递给我们的JMapper – 无需进一步配置。

Overall, this method is convenient as it uses the least amount of code.

总的来说,这种方法很方便,因为它使用的代码量最少。

6. Using XML Configuration

6.使用XML配置

We can also use XML configuration to define our mapping.

我们也可以使用XML配置来定义我们的映射。

Here’s our sample XML configuration at user_jmapper.xml:

这里是我们的XML配置样本,位于user_jmapper.xml

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

And we need to pass our XML configuration to JMapper:

而我们需要将我们的XML配置传递给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,"john@test.com", LocalDate.of(1980,8,20));
    UserDto result = userMapper.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getUsername());            
}

We can also pass the XML configuration as a String directly to JMapper instead of a file name.

我们也可以将XML配置作为String直接传递给JMapper而不是文件名。

7. Global Mapping

7.全球制图

We can take advantage of global mapping if we have multiple fields with the same name in both the source and destination beans.

如果我们在源Bean和目的Bean中有多个同名的字段,我们可以利用全局映射的优势。

For example, if we have a UserDto1 which has two fields, id and email:

例如,如果我们有一个UserDto1,它有两个字段:idemail

public class UserDto1 {  
    private long id;
    private String email;
    
    // standard constructor, getters, setters
}

Global mapping will be easier to use as they are mapped to fields with the same name at User source bean.

全局映射将更容易使用,因为它们被映射到User源Bean的同名字段上。

7.1. Using the API

7.1.使用API

For JMapperAPI configuration, we’ll use global():

对于JMapperAPI配置,我们将使用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,"john@test.com", LocalDate.of(1980,8,20));
    UserDto1 result = userMapper1.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getEmail());
}

7.2. Using Annotations

7.2.使用注解

For the annotation configuration, we’ll use @JGlobalMap at class level:

对于注解配置,我们将在类的层面上使用@JGlobalMap

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

And here’s a simple test:

而这里有一个简单的测试。

@Test
public void whenUseGlobalMapAnnotation_thenConverted(){
    JMapper<UserDto1, User> userMapper= new JMapper<>(
      UserDto1.class, User.class);
    User user = new User(
      1L,"john@test.com", LocalDate.of(1980,8,20));
    UserDto1 result = userMapper.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getEmail());        
}

7.3. XML Configuration

7.3.XML配置

And for the XML configuration, we have the <global/> element:

而对于XML配置,我们有<global/>元素。

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

And then pass the XML file name:

然后传递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,"john@test.com", LocalDate.of(1980,8,20));
    UserDto1 result = userMapper.getDestination(user);

    assertEquals(user.getId(), result.getId());
    assertEquals(user.getEmail(), result.getEmail());            
}

8. Custom Conversions

8.自定义转换

Now, let’s see how to apply a custom conversion using JMapper.

现在,让我们看看如何使用JMapper应用一个自定义转换。

We have a new field age in our UserDto, which we need to calculate from the User birthDate attribute:

我们的UserDto中有一个新字段age,我们需要从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();
    }
}

So, we used @JMapConversion to apply a complex conversion from the User’s birthDate to the UserDto’s age attribute. Therefore the age field will be calculated when we map User to UserDto:

所以,我们使用@JMapConversion来应用一个复杂的转换User的birthDateUserDto的age属性。因此,当我们将User映射到UserDto时,age字段将被计算。

@Test
public void whenUseAnnotationExplicitConversion_thenConverted(){
    JMapper<UserDto, User> userMapper = new JMapper<>(
      UserDto.class, User.class);
    User user = new User(
      1L,"john@test.com", 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. Relational Mapping

9.关系映射

Finally, we’ll discuss relational mapping. With this method, we need to define our JMapper using a target class each time.

最后,我们将讨论关系映射。通过这种方法,我们需要每次使用一个目标类来定义我们的JMapper

If we already know the target classes, we can define them for each mapped field and use RelationalJMapper.

如果我们已经知道目标类,我们可以为每个映射的字段定义它们,并使用RelationalJMapper

In this example, we have one source bean User:

在这个例子中,我们有一个源BeanUser

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

And two destination beans UserDto1:

还有两个目标BeanUserDto1

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

And UserDto2:

还有UserDto2

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

Let’s see how to take advantage of our RelationalJMapper.

让我们看看如何利用我们的RelationalJMapper.的优势。

9.1. Using the API

9.1.使用API

For our API configuration, we can define target classes for each attribute using targetClasses():

对于我们的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<User> relationalMapper = new RelationalJMapper<>
      (User.class,jmapperApi);
    User user = new User(1L,"john@test.com");
    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());            
}

Note that for each target class, we need to define the target attribute name.

注意,对于每个目标类,我们需要定义目标属性名称。

The RelationalJMapper only takes one class – the mapped class.

RelationalJMapper只接受一个类–被映射的类。

9.2. Using Annotations

9.2.使用注解

For the annotation approach, we’ll define the classes as well:

对于注释方法,我们也将定义

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

As usual, no further configuration needed when we use annotations:

像往常一样,当我们使用注释的时候,不需要进一步的配置。

@Test
public void givenUser_whenUseAnnotation_thenConverted(){
    RelationalJMapper<User> relationalMapper
      = new RelationalJMapper<>(User.class);
    User user = new User(1L,"john@test.com");
    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 Configuration

9.3.XML配置

For the XML configuration, we use <classes> to define the target classes for each attribute.

对于XML配置,我们使用<classes>来定义每个属性的目标类。

Here’s our user_jmapper2.xml:

这里是我们的user_jmapper2.xml

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

And then pass the XML configuration file to RelationalJMapper:

然后将XML配置文件传递给RelationalJMapper

@Test
public void givenUser_whenUseXml_thenConverted(){
    RelationalJMapper<User> relationalMapper
     = new RelationalJMapper<>(User.class,"user_jmapper2.xml");
    User user = new User(1L,"john@test.com");
    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. Conclusion

10.结论

In this tutorial, we learned different ways to configure JMapper and how to perform a custom conversion.

在本教程中,我们学习了配置JMapper的不同方法以及如何执行自定义转换。

The full source code for the examples can be found over on GitHub.

这些例子的完整源代码可以在GitHub上找到over