Dozer:如何限制映射的深度?

Posted

技术标签:

【中文标题】Dozer:如何限制映射的深度?【英文标题】:Dozer: How to limit the depth of mappings? 【发布时间】:2016-02-03 14:11:51 【问题描述】:

我目前正在使用 DozerEntity 对象映射到我项目中的Dto 对象。

我的问题是如何限制内部映射的级别或深度?

例如,我有一个 AccountProfile 实体,它有一个 List<AccountProfileDetail> 实体作为成员。而且AccountProfileDetail本身有一个FinancialTransLimit实体作为成员。

现在我想告诉映射器,例如只使用depth = 2 进行映射。所以FinancialTransLimit 成员不会被复制到目标对象的AccountProfileDetail 成员。

我需要指定深度使用编程 API 不在 xml 中。但是,我也没有在xml配置中找到它。

我也尝试过Orika,但我也没有在Orika中找到这样的功能!

以下两个代码(用于使用 Dozer 和 Orika 作为替代进行测试)都可以正常工作并进行深度复制。 我需要限制其中至少一个的深度

有人可以帮我解决这个问题吗?

非常感谢!

示例代码:

账户资料

//My Entities:
import java.util.List;

public class AccountProfile

    private Long id;
    private String name;
    private List<AccountProfileDetail> accountProfileDetails;

    public AccountProfile() 
    

    public Long getId() 
        return this.id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getName() 
        return this.name;
    

    public void setName(String name) 
        this.name = name;
    

    public List<AccountProfileDetail> getAccountProfileDetails() 
        return this.accountProfileDetails;
    

    public void setAccountProfileDetails(List<AccountProfileDetail> accountProfileDetails) 
        this.accountProfileDetails = accountProfileDetails;
    

账户资料详情

import java.math.BigDecimal;

public class AccountProfileDetail 

    private Long id;
    private BigDecimal accountMinBalance;
    private AccountProfile accountProfile;
    private FinancialTransLimit financialTransLimit;

    public AccountProfileDetail() 
    

    public Long getId() 
        return this.id;
    

    public void setId(Long id) 
        this.id = id;
    

    public BigDecimal getAccountMinBalance() 
        return this.accountMinBalance;
    

    public void setAccountMinBalance(BigDecimal accountMinBalance) 
        this.accountMinBalance = accountMinBalance;
    

    public AccountProfile getAccountProfile() 
        return this.accountProfile;
    

    public void setAccountProfile(AccountProfile accountProfile) 
        this.accountProfile = accountProfile;
    

    public FinancialTransLimit getFinancialTransLimit() 
        return this.financialTransLimit;
    

    public void setFinancialTransLimit(FinancialTransLimit financialTransLimit) 
        this.financialTransLimit = financialTransLimit;
    

FinancialTransLimit

public class FinancialTransLimit

    private Long id;
    private String limitCode;

    public FinancialTransLimit() 
    

    public Long getId() 
        return this.id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getLimitCode() 
        return this.limitCode;
    

    public void setLimitCode(String limitCode) 
        this.limitCode = limitCode;
    

AccountProfileDto

// My Dtos:
import java.util.List;

public class AccountProfileDto
    private Long id;
    private String name;
    private List<AccountProfileDetailDto> accountProfileDetails;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    


    public List<AccountProfileDetailDto> getAccountProfileDetails() 
        return accountProfileDetails;
    

    public void setAccountProfileDetails(List<AccountProfileDetailDto> accountProfileDetails) 
        this.accountProfileDetails = accountProfileDetails;
    

AccountProfileDetailDto

import java.math.BigDecimal;

public class AccountProfileDetailDto 

    private Long id;
    private BigDecimal accountMinBalance;
    private AccountProfileDto accountProfile;
    private FinancialTransLimitDto financialTransLimit;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public BigDecimal getAccountMinBalance() 
        return accountMinBalance;
    

    public void setAccountMinBalance(BigDecimal accountMinBalance) 
        this.accountMinBalance = accountMinBalance;
    

    public AccountProfileDto getAccountProfile() 
        return accountProfile;
    

    public void setAccountProfile(AccountProfileDto accountProfile) 
        this.accountProfile = accountProfile;
    

    public FinancialTransLimitDto getFinancialTransLimit() 
        return financialTransLimit;
    

    public void setFinancialTransLimit(FinancialTransLimitDto financialTransLimit) 
        this.financialTransLimit = financialTransLimit;
    

FinancialTransLimitDto

public class FinancialTransLimitDto 
    private Long id;
    private String limitCode;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getLimitCode() 
        return limitCode;
    

    public void setLimitCode(String limitCode) 
        this.limitCode = limitCode;
    

现在是 Dozer 的测试用例代码:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;


public class TestDozer 

    public static void main(String[] args) 

        List<AccountProfile> profiles = createList();

        Mapper mapper = new DozerBeanMapper();

        List<AccountProfileDto> profileDtos = new ArrayList<AccountProfileDto>(); 

        for (AccountProfile entity: profiles) 
            AccountProfileDto dto = new AccountProfileDto();
            mapper.map(entity, dto);
            profileDtos.add(dto);
        

        System.out.println(Arrays.deepToString(profileDtos.toArray()));
    

    private static List<AccountProfile> createList()
        List<AccountProfile> accountProfiles = new ArrayList<AccountProfile>();

        AccountProfile ap1 = new AccountProfile();
        ap1.setId(new Long(1000));
        ap1.setName("profile1");

        FinancialTransLimit ftlt1 = new FinancialTransLimit();
        ftlt1.setId(new Long(3000));
        ftlt1.setLimitCode("L1");

        AccountProfileDetail apd1 = new AccountProfileDetail();
        apd1.setId(new Long(2000));
        apd1.setAccountProfile(ap1);
        apd1.setAccountMinBalance(new BigDecimal(100000));
        apd1.setFinancialTransLimit(ftlt1);

        List<AccountProfileDetail> apds1 = new ArrayList<AccountProfileDetail>();
        apds1.add(apd1);
        ap1.setAccountProfileDetails(apds1);

        accountProfiles.add(ap1);
        //
        AccountProfile ap2 = new AccountProfile();
        ap2.setId(new Long(1001));
        ap2.setName("profile2");

        FinancialTransLimit ftlt2 = new FinancialTransLimit();
        ftlt2.setId(new Long(3001));
        ftlt2.setLimitCode("L2");

        AccountProfileDetail apd2 = new AccountProfileDetail();
        apd2.setId(new Long(2001));
        apd2.setAccountProfile(ap2);
        apd2.setAccountMinBalance(new BigDecimal(200000));
        apd2.setFinancialTransLimit(ftlt2);

        List<AccountProfileDetail> apds2 = new ArrayList<AccountProfileDetail>();
        apds2.add(apd2);
        ap2.setAccountProfileDetails(apds2);

        accountProfiles.add(ap2);
        //
        return accountProfiles;
    

Orika测试代码:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import ma.glasnost.orika.BoundMapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;

public class TestOrika 

    public static void main(String[] args) 

        List<AccountProfile> profiles = createList();

        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        BoundMapperFacade<AccountProfile, AccountProfileDto> mapper = mapperFactory.getMapperFacade(AccountProfile.class, AccountProfileDto.class);

        List<AccountProfileDto> profileDtos = new ArrayList<AccountProfileDto>(); 

        for (AccountProfile entity: profiles) 
            AccountProfileDto dto = new AccountProfileDto();
            mapper.map(entity, dto);
            profileDtos.add(dto);
        

        System.out.println(Arrays.deepToString(profileDtos.toArray()));
    

    private static List<AccountProfile> createList()
        List<AccountProfile> accountProfiles = new ArrayList<AccountProfile>();

        AccountProfile ap1 = new AccountProfile();
        ap1.setId(new Long(1000));
        ap1.setName("profile1");

        FinancialTransLimit ftlt1 = new FinancialTransLimit();
        ftlt1.setId(new Long(3000));
        ftlt1.setLimitCode("L1");

        AccountProfileDetail apd1 = new AccountProfileDetail();
        apd1.setId(new Long(2000));
        apd1.setAccountProfile(ap1);
        apd1.setAccountMinBalance(new BigDecimal(100000));
        apd1.setFinancialTransLimit(ftlt1);

        List<AccountProfileDetail> apds1 = new ArrayList<AccountProfileDetail>();
        apds1.add(apd1);
        ap1.setAccountProfileDetails(apds1);

        accountProfiles.add(ap1);

        //

        AccountProfile ap2 = new AccountProfile();
        ap2.setId(new Long(1001));
        ap2.setName("profile2");

        FinancialTransLimit ftlt2 = new FinancialTransLimit();
        ftlt2.setId(new Long(3001));
        ftlt2.setLimitCode("L2");

        AccountProfileDetail apd2 = new AccountProfileDetail();
        apd2.setId(new Long(2001));
        apd2.setAccountProfile(ap2);
        apd2.setAccountMinBalance(new BigDecimal(200000));
        apd2.setFinancialTransLimit(ftlt2);

        List<AccountProfileDetail> apds2 = new ArrayList<AccountProfileDetail>();
        apds2.add(apd2);
        ap2.setAccountProfileDetails(apds2);

        accountProfiles.add(ap2);

        //

        return accountProfiles;
    

【问题讨论】:

你有代码要分享吗? @cheffe:明天我会分享我的代码示例。 @cheffe:我添加了一些代码。 【参考方案1】:

我认为这在我使用的上一个版本 (5.5.X) 中是不可能的。推土机将尝试将对象从一个映射到另一个,直到他到达终点。如果他找到循环关系,就会抛出异常。此外,如果两个对象具有名称相同的不同类型的属性,则会引发异常。这就是使用第 3 方映射器库的全部意义所在。 但是,如果目标对象不包含可在源映射期间使用的属性,则该属性将被忽略。如果您以不同的方式命名目标属性,理论上应该同样有效。您可以使用这些规则制定一些技巧。

我建议您仅在源对象和目标对象之间没有差异的 1 对 1 映射时才坚持使用 Dozer。如果您对如何映射它有不同或限制,请编写您自己的转换器。

【讨论】:

以上是关于Dozer:如何限制映射的深度?的主要内容,如果未能解决你的问题,请参考以下文章

Dozer-对象属性映射工具类

SpringBoot2.x 集成 Dozer

使用 Dozer 的自定义转换器将对象列表映射到另一个列表

CISCN_Dozer战队wp

每个 allowed_domains 的 Scrapy 设置深度限制

在 React 中限制映射值的字符长度