Search code examples
javamodeldto

Problems in mapping objects between the model and DTO


I am mapping between the following models:

@Entity
@Table(name="account_type")
@NamedQuery(name="AccountType.findAll", query="SELECT a FROM AccountType a")
public class AccountType implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name="account_type_id")
    private Integer accountTypeId;

    @Column(name="account_type_code")
    private String accountTypeCode;

    @OneToMany(mappedBy="accountType")
    private Set<Account> accounts;

Which has a set of Account:

@Entity
@NamedQuery(name="Account.findAll", query="SELECT a FROM Account a")
public class Account implements Serializable {
    private static final long serialVersionUID = 1L;

@Id
@GeneratedValue
@Column(name="account_id")
private Integer accountId;

@Column(name="account_number")
private String accountNumber;

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="account_type_id_fk")
private AccountType accountType;

And their DTOs.

I am having problems in mapping complex types like Account:

public static Account getAccount(AccountDTO dto) {
        Account model = new Account();
        
        model.setAccountId(dto.getAccountId());
        model.setAccountNumber(dto.getAccountNumber());
        
        model.setAccountType(dto.getAccountType());
        // Error: can't convert from AccountypeDTO to AccountType

        return model;
    }

It gives an error that it can't convert from AccountypeDTO to AccountType

so I did the following:

model.setAccountType(getAccountType(dto.getAccountType()));

Where getAccountType method is:

public static AccountType getAccountType(AccountTypeDTO dto) {
        
        AccountType model = new AccountType();

        model.setAccountTypeId(dto.getAccountTypeId());
        model.setAccountTypeCode(dto.getAccountTypeCode());

        model.setAccounts(dto.getAccounts());
        // Now here again a similar error
    }

I think it's a deep recursive? How to solve this?

My question is how to convert them efficiently.

Annex


The code of acountTypeDTO:

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountTypeDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    @NotNull
    @NotEmpty
    private Integer accountTypeId;

    @NotNull
    @NotEmpty
    private String accountTypeCode;

    private Set<AccountDTO> accounts;

The code of AccountDTO:

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    @NotNull
    @NotEmpty
    private Integer accountId;

    @NotNull
    @NotEmpty
    private String accountNumber;

    private AccountTypeDTO accountType;

Solution

  • Two alternative approaches jump to mind but they will require some change. I will preface this by saying that I have yet to be in a situation where converting to DTOs (even if I'm doing a deep recursive conversion) is the bottleneck. Even if your performance requirements or your scale were so large that it somehow did become a bottleneck then I would personally recommend dividing the work across multiple servers before I started to worry about performance down to that level of detail. Also, it may seem inefficient but performance is rarely intuitive, have you confirmed that this conversion is a bottleneck?

    The first alternative is to not use separate classes as DTOs. Some approaches use the same class as the DTO and the underlying entities and some approaches use the DTO as the parent class and the entity class as the child class. This will save you from having to do any kind of DTO<->Entity conversion. There are drawbacks, as this almost always ends up combining two responsibilities into a single class and it can make your code more complex and less readable.

    The second alternative is to not return the accounts themselves but instead to convert them to IDs. In this approach your AccountTypeDTO would have a Set<Integer> accountIds instead of a Set<AccountDTO> accounts. However, this only works if your client doesn't always need to operate on every account.