Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dozer: How to limit the depth of mappings?

I'm currently using Dozer for mapping Entity objects to Dto objects in my project.

My question is how to limit the levels or the depth of internal mappings?

For example I have a AccountProfile entity which has a List<AccountProfileDetail> entity as a member. Moreover AccountProfileDetail itself has a FinancialTransLimit entity as a member.

Now I want to tell the mapper that for example do the mappings only with depth = 2. So the FinancialTransLimit member doesn't get copied to the AccountProfileDetail member of destination object.

I need to specify the depth using Programming API not in xml. However, I didn't find it in the xml configurations, too.

I've tried Orika too, but I couldn't find such feature in Orika too!

Both of the following codes (for testing with Dozer and Orika as an alternative) work fine and do a deep copy. I need to limit the depth for at least one of them.

Could anyone help me with this, please?

Many thanks!

Sample Code:

AccountProfile

//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;
    }
}

AccountProfileDetail

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

And now the test case code with 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;
    }
}

Test code with 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;
    }
}
like image 794
STaefi Avatar asked Nov 03 '15 12:11

STaefi


1 Answers

I don't think that was possible in the last version I used (5.5.X). Dozer will try to map objects from one to another until he hits the end. If he finds a circular relations, it will throw an exception. Also, exception will be thrown if two objects have attributes of different types named the same. That is the whole point of using the 3th party mapper library. However, if the target object does not contain the attribute that could be used during mapping of source, that attribute will just be ignored. Same should theoretically work if you name the target-attributes differently. You can work out some hacks using these rules.

I would advise you to stick with Dozer only if you have 1 to 1 mappings with no difference in source and target objects. If you have differences or constraints on how you want to map it, write your own converters.

like image 157
Vanja Lee Avatar answered Oct 31 '22 09:10

Vanja Lee