I'm creating an API that transmits data from another web service. I'm looking for good practice to convert the objects from the web service to my DTO's. The conversion from the object to DTO has some logic.
I have now implemented this (pseudo-code):
I have a main builder that contains generic code that the other builders can use.
@Component
public abstract class RelationDtoBuilder <T extends RelationDtoBuilder <T>> {
protected abstract T getThis();
@Autowired
private PhoneNumberDtoBuilder phoneNumberDtoBuilder ;
protected List<PhoneNumberDto> phoneNumbers= new ArrayList<>();
public T setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
if (phoneNumbers!= null) {
phoneNumbers.stream().forEach(phoneNumber -> {
this.phoneNumbers.add(
phoneNumberDtoBuilder
.setNumber(branch.getNumber())
.setType(branch.getType())
.build()
); });
}
return getThis();
}
}
Subclass builder for a PersonDto
@Component
public final class PersonDtoBuilder extends RelationDtoBuilder<PersonDtoBuilder> {
@Override
protected PersonDtoBuilder getThis() {
return this;
}
public PersonDto build() {
PersonDto personDto = new PersonDto();
PersonDto.setPhoneNumbers(super.phoneNumbers);
return PersonDto;
}
}
Subclass builder for a CompanyDto
@Component
public final class CompanyDtoBuilder extends RelationDtoBuilder<CompanyDtoBuilder > {
protected List<BranchDto> branches = new ArrayList<>();
@Override
protected CompanyDtoBuilder getThis() {
return this;
}
public CompanyDtoBuilder setBranches(List<Branch> branches) {
if (branches != null) {
branches.stream().forEach(branch -> {
this.branches.add(
branchDtoBuilder
.setName(branch.getName())
.setType(branch.getType())
.setPhoneNumbers(branch.getPhoneNumbers)
.build()
);
});
}
return getThis();
}
public CompanyDtoBuilder build() {
CompanyDto companyDto= new CompanyDto ();
companyDto.setPhoneNumbers(super.phoneNumbers);
companyDto.setBranches(this.branches);
return CompanyDto;
}
}
BranchDtoBuilder
@Component
public final class BranchDtoBuilder extends RelationDtoBuilder<PersonDtoBuilder>{
@Autowired
private ValueConverterService valueConverterService;
private String name;
private String type;
@Override
protected BranchDtoBuilder getThis() {
return this;
}
public BranchDtoBuilder setName(String name) {
this.name= name;
return this;
}
public BranchDtoBuilder setType(String type) {
if (type != null) {
this.type= valueConverterService.convertValue("branchType", type);
}
return this;
}
public BranchDtoBuilder build() {
BranchDto branchDto = new branchDto();
branchDto.setSoort(this.soort);
branchDto.setWaarde(this.waarde);
branchDto.setPhoneNumbers(this.datumIngang);
return branchDto ;
}
}
Problem is that de BranchDtoBuilder is using the same reference for phone numbers as the CompanyDtoBuilder. How can I achieve constructing the DTO's without having duplicate code?
Secondly, is this the best way to map entities to DTO's with logic as database conversions (BranchDtoBuilder)?