自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MapStruct教程-操作三種集合類型和兩個(gè)關(guān)鍵點(diǎn)

開發(fā) 前端
MapStruct提供了一種選擇如何將子類型設(shè)置或添加到父類型的方法。特別是,@Mapper注解有一個(gè)collectionMappingStrategy屬性,可以是ACCESSOR_ONLY、SETTER_PREFERRED、ADDER_PREFERRED或TARGET_IMMUTABLE。

今天我們一起看下,如何使用MapStruct映射對(duì)象集合。

一、映射集合

通常來說,使用MapStruct映射集合的方式與映射簡(jiǎn)單類型相同。

我們需要?jiǎng)?chuàng)建一個(gè)簡(jiǎn)單的接口或抽象類,并聲明映射方法。

根據(jù)我們的聲明,MapStruct將自動(dòng)生成映射代碼。

通常,生成的代碼會(huì)遍歷源集合,將每個(gè)元素轉(zhuǎn)換為目標(biāo)類型,并將它們包含在目標(biāo)集合中。

讓我們看一個(gè)簡(jiǎn)單的例子。

(一)映射List

首先,我們將一個(gè)簡(jiǎn)單的POJO作為映射器的映射源:

public 
class 
Employee 
{
    
private String firstName;
    
private String lastName;
}

目標(biāo)將是一個(gè)簡(jiǎn)單的DTO:

public 
class 
EmployeeDTO 
{
    
private String firstName;
    
private String lastName;
}

接下來,我們定義映射器:

@Mapper
public 
interface 
EmployeeMapper 
{
    
List<EmployeeDTO> map(List<Employee> employees);
}

最后,讓我們看看MapStruct從EmployeeMapper接口生成的代碼:

public 
class 
EmployeeMapperImpl 
implements 
EmployeeMapper 
{

    
@Override
    
public List<EmployeeDTO> map(List<Employee> employees) 
{
        
if ( employees == null ) {
            
return 
null;
        }

        List<EmployeeDTO> list = new ArrayList<EmployeeDTO>( employees.size() );
        
for ( Employee employee : employees ) {
            list.add( employeeToEmployeeDTO( employee ) );
        }

        
return list;
    }

    
protected EmployeeDTO employeeToEmployeeDTO(Employee employee) 
{
        
if ( employee == null ) {
            
return 
null;
        }

        EmployeeDTO employeeDTO = new EmployeeDTO();

        employeeDTO.setFirstName( employee.getFirstName() );
        employeeDTO.setLastName( employee.getLastName() );

        
return employeeDTO;
    }
}

需要注意的是,MapStruct會(huì)自動(dòng)為我們生成了從Employee到EmployeeDTO的映射方法。

需要注意,自動(dòng)生成的映射方法只會(huì)匹配字段名一致的情況,如果名字不一致,就不行了。

比如:

public 
class 
EmployeeFullNameDTO 
{
    
private String fullName;
}

在這種情況下,如果我們只是聲明從Employee列表到EmployeeFullNameDTO列表的映射方法,最終是沒有任何字段賦值的,MapStruct無法自動(dòng)為我們生成映射,如果沒有配置忽略邏輯(參考MapStruct教程(四)-忽略未映射屬性的三種方式),編譯時(shí)會(huì)拋出異常:

[WARNING] /path/to/EmployeeMapper.java:[15,31] Unmapped target property: "fullName". Mapping from Collection element "Employee employee" to "EmployeeFullNameDTO employeeFullNameDTO".

因此,我們需要手動(dòng)定義Employee和EmployeeFullNameDTO之間的映射。

鑒于這些要點(diǎn),讓我們手動(dòng)定義它:

@Mapper
public 
interface 
EmployeeFullNameMapper 
{
    
List<EmployeeFullNameDTO> map(List<Employee> employees);

    
@Mapping(target = "fullName", expression = "java(employee.getFirstName() + \" \" + employee.getLastName())")
    
EmployeeFullNameDTO map(Employee employee);
}

生成的代碼將使用我們定義的方法將源列表的元素映射到目標(biāo)列表:

public 
class 
EmployeeFullNameMapperImpl 
implements 
EmployeeFullNameMapper 
{

    
@Override
    
public List<EmployeeFullNameDTO> map(List<Employee> employees) 
{
        
if ( employees == null ) {
            
return 
null;
        }

        List<EmployeeFullNameDTO> list = new ArrayList<EmployeeFullNameDTO>( employees.size() );
        
for ( Employee employee : employees ) {
            list.add( map( employee ) );
        }

        
return list;
    }

    
@Override
    
public EmployeeFullNameDTO map(Employee employee) 
{
        
if ( employee == null ) {
            
return 
null;
        }

        EmployeeFullNameDTO employeeFullNameDTO = new EmployeeFullNameDTO();

        employeeFullNameDTO.setFullName( employee.getFirstName() + " " + employee.getLastName() );

        
return employeeFullNameDTO;
    }
}

(二)映射Set和Map

使用MapStruct映射Set的方式與List相同。

例如,假設(shè)我們要將一組Employee實(shí)例映射到一組EmployeeDTO實(shí)例。

和之前一樣,我們需要一個(gè)映射器:

@Mapper
public 
interface 
EmployeeMapper 
{
    
Set<EmployeeDTO> map(Set<Employee> employees);
}

然后MapStruct將生成相應(yīng)的代碼:

@Override
public Set<EmployeeDTO> map(Set<Employee> employees) 
{
    
if ( employees == null ) {
        
return 
null;
    }

    Set<EmployeeDTO> set = new LinkedHashSet<EmployeeDTO>( Math.max( (int) ( employees.size() / .75f ) + 1, 16 ) );
    
for ( Employee employee : employees ) {
        set.add( employeeToEmployeeDTO( employee ) );
    }

    
return set;
}

對(duì)于Map也是如此。

假設(shè)我們要將一個(gè)Map<String, Employee>映射到一個(gè)Map<String, EmployeeDTO>。

我們可以按照之前的相同步驟進(jìn)行操作:

@Mapper
public 
interface 
EmployeeMapper 
{

    
Map<String, EmployeeDTO> map(Map<String, Employee> idEmployeeMap);
}

MapStruct編譯后的結(jié)果:

@Override
public Map<String, EmployeeDTO> map(Map<String, Employee> idEmployeeMap) 
{
    
if ( idEmployeeMap == null ) {
        
return 
null;
    }

    Map<String, EmployeeDTO> map = new LinkedHashMap<String, EmployeeDTO>( Math.max( (int) ( idEmployeeMap.size() / .75f ) + 1, 16 ) );

    
for ( java.util.Map.Entry<String, Employee> entry : idEmployeeMap.entrySet() ) {
        String key = entry.getKey();
        EmployeeDTO value = employeeToEmployeeDTO( entry.getValue() );
        map.put( key, value );
    }

    
return map;
}

可以看到,無論是Set還是Map,MapStruct在初始化容器的時(shí)候,都會(huì)指定容器大小,優(yōu)秀的工具細(xì)節(jié)方面都是很好的。

二、集合映射策略

有時(shí)候,我們還會(huì)用到有父子關(guān)系的數(shù)據(jù)類型:一個(gè)數(shù)據(jù)類型(父類型),它有一個(gè)包含另一個(gè)數(shù)據(jù)類型(子類型)的集合字段。

對(duì)于這種情況,MapStruct提供了一種選擇如何將子類型設(shè)置或添加到父類型的方法。特別是,@Mapper注解有一個(gè)collectionMappingStrategy屬性,可以是ACCESSOR_ONLY、SETTER_PREFERRED、ADDER_PREFERRED或TARGET_IMMUTABLE。所有這些值都指的是將子類型設(shè)置或添加到父類型的方式。

默認(rèn)值是ACCESSOR_ONLY,即只能使用訪問器來設(shè)置子類型的集合。

(一)ACCESSOR_ONLY策略

我們通過例子看看。首先,我們創(chuàng)建一個(gè)Company類作為我們的源類型:

public 
class 
Company 
{
    
private List<Employee> employees;
}

再定義一個(gè)DTO作為目標(biāo)類型:

public 
class 
CompanyDTO 
{
    
private List<EmployeeDTO> employees;

    
public List<EmployeeDTO> getEmployees() 
{
        
return employees;
    }

    
public 
void 
setEmployees(List<EmployeeDTO> employees) 
{
        
this.employees = employees;
    }

    
public 
void 
addEmployee(EmployeeDTO employeeDTO) 
{
        
if (employees == null) {
            employees = new ArrayList<>();
        }

        employees.add(employeeDTO);
    }
}

注意,在這里我們定義了setter和adder兩種方法,adder中做了屬性初始化。

為什么要定義setter和adder?接下看。

如果我們需要將一個(gè)Company映射到一個(gè)CompanyDTO,定義一個(gè)映射器:

@Mapper(uses = EmployeeMapper.class, collectionMappingStrategy 
= ACCESSOR_ONLY)
public 
interface 
CompanyMapper 
{
    
CompanyDTO map(Company company);
}

我們這里復(fù)用了EmployeeMapper,并定義了collectionMappingStrategy屬性是ACCESSOR_ONLY(默認(rèn)是ACCESSOR_ONLY,所以也可以忽略)。

現(xiàn)在讓我們看看MapStruct生成的代碼:

public 
class 
CompanyMapperImpl 
implements 
CompanyMapper 
{

    
private 
final EmployeeMapper employeeMapper = Mappers.getMapper( EmployeeMapper.class );

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

        CompanyDTO companyDTO = new CompanyDTO();

        companyDTO.setEmployees( employeeMapper.map( company.getEmployees() ) );

        
return companyDTO;
    }
}

如上,MapStruct使用setter(setEmployees)來設(shè)置EmployeeDTO實(shí)例的列表,這是因?yàn)槲覀兪褂昧薃CCESSOR_ONLY方式操作集合。

而且,MapStruct使用了EmployeeMapper的將List映射到List的方法。

(二)ADDER_PREFERRED策略

如果我們使用ADDER_PREFERRED策略:

@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
        uses = EmployeeMapper.class)
public 
interface 
CompanyMapperAdderPreferred 
{
    
CompanyDTO map(Company company);
}

ADDER_PREFERRED策略是一個(gè)一個(gè)的追加,我們?cè)贓mployeeMapper中創(chuàng)建單個(gè)Employee轉(zhuǎn)換為EmployeeDTO的方法:

EmployeeDTO map(Employee employee);

當(dāng)然,也可以不用增加單個(gè)對(duì)象映射的方法,因?yàn)镸apStruct會(huì)自動(dòng)生成,不過,為了系統(tǒng)邊界清晰,還是單獨(dú)定義比較好。

生成的映射器代碼是:

public 
class 
CompanyMapperAdderPreferredImpl 
implements 
CompanyMapperAdderPreferred 
{

    
private 
final EmployeeMapper employeeMapper = Mappers.getMapper( EmployeeMapper.class );

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

        CompanyDTO companyDTO = new CompanyDTO();

        
if ( company.getEmployees() != null ) {
            
for ( Employee employee : company.getEmployees() ) {
                companyDTO.addEmployee( employeeMapper.map( employee ) );
            }
        }

        
return companyDTO;
    }
}

如果CompanyDTO中沒有adder方法,也會(huì)再使用setter方法。

三、目標(biāo)集合的實(shí)現(xiàn)類型

MapStruct支持將集合接口作為映射方法的目標(biāo)類型。

在這種情況下,生成的代碼中使用了一些默認(rèn)實(shí)現(xiàn)。如下是對(duì)應(yīng)關(guān)系:

接口類型

實(shí)現(xiàn)類型

Iterable

ArrayList

Collection

ArrayList

List

ArrayList

Set

LinkedHashSet

SortedSet

TreeSet

NavigableSet

TreeSet

Map

LinkedHashMap

SortedMap

TreeMap

NavigableMap

TreeMap

ConcurrentMap

ConcurrentHashMap

ConcurrentNavigableMap

ConcurrentSkipListMap

責(zé)任編輯:武曉燕 來源: 看山的小屋
相關(guān)推薦

2025-01-13 00:00:00

MapStruct繼承關(guān)系Java

2011-01-18 15:35:59

jQueryJavaScriptweb

2016-10-25 13:58:36

數(shù)據(jù)圖表化大數(shù)據(jù)

2022-06-20 08:50:16

TypeScript類型語法

2025-01-13 00:00:00

MapStruct枚舉映射

2010-06-08 09:39:40

UML圖

2023-10-13 00:00:00

Redis模塊空間對(duì)象

2010-09-09 10:43:56

VPN服務(wù)

2025-01-16 00:00:00

MapStruct映射

2009-08-06 15:26:18

C#異常類型

2009-11-06 10:54:19

WCF服務(wù)方式

2024-05-30 08:03:17

2024-06-04 17:02:38

newC#編程語言

2021-04-22 09:00:48

工業(yè)物聯(lián)網(wǎng)IIOT物聯(lián)網(wǎng)

2009-06-29 18:21:29

Hibernate

2010-05-11 14:08:50

MySQL數(shù)字類型

2009-12-10 15:46:22

動(dòng)態(tài)路由協(xié)議

2018-12-13 20:14:18

物聯(lián)網(wǎng)平臺(tái)物聯(lián)網(wǎng)IOT

2019-12-02 14:14:20

緩沖系統(tǒng)調(diào)用函數(shù)

2012-08-10 14:38:13

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)