使用MapStruct映射集合

1.映射集合

通常,使用MapStruct映射集合的方式与使用简单类型的方式相同。

基本上,必须创建一个简单的接口或抽象类并声明映射方法。 根据声明,MapStruct将自动生成映射代码。 通常,生成的代码将遍历源集合,将每个元素转换为目标类型,并将每个元素包括在目标集合中。

1.1映射List

创建简单的映射类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String firstName;
    private String lastName;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
    private String firstName;
    private String lastName;
}

定义映射

@Mapper(componentModel = "spring")
public interface UserMapper {
    List map(List users);
}

下面为mapstruct生成的实现类

@Component
public class UserMapperImpl implements UserMapper {

    @Override
    public List<UserDTO> map(List<User> users) {
        if ( users == null ) {
            return null;
        }

        List<UserDTO> list = new ArrayList<UserDTO>( users.size() );
        for ( User user : users ) {
            list.add( userToUserDTO( user ) );
        }

        return list;
    }

    protected UserDTO userToUserDTO(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setFirstName( user.getFirstName() );
        userDTO.setLastName( user.getLastName() );

        return userDTO;
    }
}

有一件重要的事情要注意。 具体来说,MapStruct为自动生成了从User到UserDTO的映射。

在某些情况下,这是不可能的。 例如,假设要将User模型映射到以下模型:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserFullNameDTO {
    private String fullName;
}

在这种情况下,如果仅声明从User列表到UserFullNameDTO列表的映射方法,将收到编译时错误或警告,例如:

E:\koal_code\demo\src\main\java\com\example\demo\mapstruct\UserMapper.java
Warning:(14, 21) java: Unmapped target property: "fullName".

基本上,这意味着MapStruct无法在这种情况下为自动生成映射。 因此,需要手动定义User和UserFullNameDTO之间的映射。

手动定义:

@Mapper(componentModel = "spring")
public interface UserMapper {
    List<UserDTO> map(List<User> users);
    
    List<UserFullNameDTO> mapToFullList(List<User> users);
    
    default UserFullNameDTO mapUserFullName(User user) {
        UserFullNameDTO employeeInfoDTO = new UserFullNameDTO();
        employeeInfoDTO.setFullName(user.getFirstName() + " " + user.getLastName());

        return employeeInfoDTO;
    }
}

2.2映射Set和Map

MapStruct的映射集的工作方式与列表相同。 例如,假设要将User实例集映射到UserDTO实例集。

和以前一样,需要一个映射器:

@Mapper(componentModel = "spring")
public interface UserMapper {
    Set<UserDTO> map(Set<User> users);
}

然后MapStruct将生成适当的代码:

@Component
public class UserMapperImpl implements UserMapper {

    @Override
    public Set map(Set users) {
        if ( users == null ) {
            return null;
        }

        Set set = new HashSet( Math.max( (int) ( users.size() / .75f ) + 1, 16 ) );
        for ( User user : users ) {
            set.add( userToUserDTO( user ) );
        }

        return set;
    }

    protected UserDTO userToUserDTO(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setFirstName( user.getFirstName() );
        userDTO.setLastName( user.getLastName() );

        return userDTO;
    }
}

Map也是如此。将Map 映射到Map。可以按照与之前相同的步骤进行操作:

@Mapper(componentModel = "spring")
public interface UserMapper {
    Map<String, UserDTO> map(Map<String, User> idUserMap);
}

MapStruct将生成适当的代码:

@Component
public class UserMapperImpl implements UserMapper {

    @Override
    public Map<String, UserDTO> map(Map<String, User> idUserMap) {
        if ( idUserMap == null ) {
            return null;
        }

        Map<String, UserDTO> map = new HashMap<String, UserDTO>( Math.max( (int) ( idUserMap.size() / .75f ) + 1, 16 ) );

        for ( java.util.Map.Entry<String, User> entry : idUserMap.entrySet() ) {
            String key = entry.getKey();
            UserDTO value = userToUserDTO( entry.getValue() );
            map.put( key, value );
        }

        return map;
    }

    protected UserDTO userToUserDTO(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setFirstName( user.getFirstName() );
        userDTO.setLastName( user.getLastName() );

        return userDTO;
    }
}

2.集合映射策略

需要映射具有父子关系的数据类型。 通常,有一个数据类型(父级),该字段具有另一个数据类型(子级)的Collection作为字段。

对于此类情况,MapStruct提供了一种选择如何设置子代或将子代添加到父代类型的方法。 特别地,@Mapper批注具有collectionMappingStrategy属性,该属性可以是ACCESSOR_ONLY,SETTER_PREFERRED,ADDER_PREFERRED或TARGET_IMMUTABLE。

所有这些值都涉及应设置子代或将其添加到父代类型的方式。 默认值为ACCESSOR_ONLY,这意味着只能使用访问器来设置子级的Collection。

2.1 ACCESSOR_ONLY集合映射策略

举个例子来更好地理解是如何工作的。

创建一个Company类作为映射源

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company {
    private List<User> users;
}

请注意,既有setter setUsers,又有加法器addUser。 同样,对于加法器,负责集合的初始化。

public class CompanyDTO {

    private List<UserDTO> users;

    public List<UserDTO> getUsers() {
        return users;
    }

    public void setUsers(List<UserDTO> users) {
        this.users = users;
    }

    public void addEmployee(UserDTO userDTO) {
        if (users == null) {
            users = new ArrayList<>();
        }

        users.add(userDTO);
    }
}

映射器

@Mapper(componentModel = "spring",uses = UserMapper.class)
public interface CompanyMapper {
    CompanyDTO map(Company company);
}

请注意,使用UserMapper和默认的collectionMappingStrategy。

现在,看一下MapStruct生成的代码:

@Component
public class CompanyMapperImpl implements CompanyMapper {

    @Autowired
    private UserMapper userMapper;

    @Override
    public CompanyDTO map(Company company) {
        if ( company == null ) {
            return null;
        }

        CompanyDTO companyDTO = new CompanyDTO();

        companyDTO.setUsers( userMapper.map( company.getUsers() ) );

        return companyDTO;
    }
}

可以看出,MapStruct使用setUsers来设置UserDTO实例列表。 这里使用默认的collectionMappingStrategy ACCESSOR_ONLY。

此外,MapStruct在UserMapper中找到了一种将List 映射到List 的方法,然后重新使用它。

2.2 ADDER_PREFERRED集合映射策略

@Mapper(componentModel = "spring",collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,uses = UserMapper.class)
public interface CompanyMapper {
    CompanyDTO map(Company company);
}

要重用UserMapper.需要显式添加一个首先可以将单个User转换为UserDTO的方法:

@Mapper(componentModel = "spring")
public interface UserMapper {    UserDTO map(User user);}

这是因为MapStruct将使用加法器将UserDTO实例一一添加到目标CompanyDTO实例,生成的实现类

@Component
public class CompanyMapperImpl implements CompanyMapper {

    @Autowired
    private UserMapper userMapper;

    @Override
    public CompanyDTO map(Company company) {
        if ( company == null ) {
            return null;
        }

        CompanyDTO companyDTO = new CompanyDTO();

        if ( company.getUsers() != null ) {
            for ( User user : company.getUsers() ) {
                companyDTO.addEmployee( userMapper.map( user ) );
            }
        }

        return companyDTO;
    }
}

在这里插入图片描述

你可能感兴趣的:(MapStruct)