[java] DTO pattern: Best way to copy properties between two objects

In my application's architecture I usually send the object or list of objects from the data access layer to the web layer via the service layer, in which these objects get transformed from a DAO object to a DTO object and vice versa. The web layer don't have any access to DAO objects and the DAO layer do not use DTOs.

To demonstrate, I usually write the code as:

@Transactional(readOnly = true)
public List<UserDTO> getAllUserAsUserDTO() {
    List<UserDTO> userDTOs = new ArrayList<UserDTO>();

    for(User user : getAllUser()) {
        userDTOs.add(constructUserDTO(user));
    }

    return userDTOs;
}

private UserDTO constructUserDTO(User user) {
    UserDTO userDTO = new UserDTO();
    userDTO.setFullName(user.getFullName());
    userDTO.setId(user.getId());
    userDTO.setUsername(user.getUsername());
    userDTO.setRole(user.getRole());
    userDTO.setActive(user.isActive());
    userDTO.setActiveText(user.isActive() ? "Active" : "Inactive");
    return userDTO;
}

Here the user is the database entity:

@javax.persistence.Entity
@Table(name = "USER")
public class User extends Entity {

    @Transient
    private static final long serialVersionUID = -112950002831333869L;

    private String username;
    private String fullName;
    private boolean active;
    private String role;
    // other fields

    public User() {
        super();
    }

    @NaturalId
    @Column(name = "USERNAME", nullable = false)
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Column(name = "FULL_NAME")
    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    @Column(name = "ACTIVE", nullable = false)
    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    @Column(name = "ROLE")
    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

And this is the UserDTO:

public class UserDTO extends BaseDTO {

    private static final long serialVersionUID = -3719463614753533782L;

    private String username;
    private String fullName;
    private String role;
    private String activeText;
    private Boolean active;
    //other properties

    public UserDTO() {
        super();
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getActiveText() {
        return activeText;
    }

    public void setActiveText(String activeText) {
        this.activeText = activeText;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }
}

So I was wondering if this is the only way to copy properties between two objects. I guess I am not sure. Also I am using lambdaj, so is there a method in this API by which I can copy all these properties to create list of other objects?

This topic may be sounds subjective, but I really want to know from you experts the ways by which the transformation of object from one form to another can be done where the maximum fields are having same string.

This question is related to java object lambdaj

The answer is


You can use reflection to find all the get methods in your DAO objects and call the equivalent set method in the DTO. This will only work if all such methods exist. It should be easy to find example code for this.


I had an application that I needed to convert from a JPA entity to DTO, and I thought about it and finally came up using org.springframework.beans.BeanUtils.copyProperties for copying simple properties and also extending and using org.springframework.binding.convert.service.DefaultConversionService for converting complex properties.

In detail my service was something like this:

@Service("seedingConverterService")
public class SeedingConverterService extends DefaultConversionService implements ISeedingConverterService  {
    @PostConstruct
    public void init(){
        Converter<Feature,FeatureDTO> featureConverter = new Converter<Feature, FeatureDTO>() {

            @Override
            public FeatureDTO convert(Feature f) {
                FeatureDTO dto = new FeatureDTO();
                //BeanUtils.copyProperties(f, dto,"configurationModel");
                BeanUtils.copyProperties(f, dto);
                dto.setConfigurationModelId(f.getConfigurationModel()==null?null:f.getConfigurationModel().getId());
                return dto;
            }
        };

        Converter<ConfigurationModel,ConfigurationModelDTO> configurationModelConverter = new Converter<ConfigurationModel,ConfigurationModelDTO>() {
            @Override
            public ConfigurationModelDTO convert(ConfigurationModel c) {
                ConfigurationModelDTO dto = new ConfigurationModelDTO();
                //BeanUtils.copyProperties(c, dto, "features");
                BeanUtils.copyProperties(c, dto);
                dto.setAlgorithmId(c.getAlgorithm()==null?null:c.getAlgorithm().getId());
                List<FeatureDTO> l = c.getFeatures().stream().map(f->featureConverter.convert(f)).collect(Collectors.toList());
                dto.setFeatures(l);
                return dto;
            }
        };
        addConverter(featureConverter);
        addConverter(configurationModelConverter);
    }
}

I suggest you should use one of the mappers' libraries: Mapstruct, ModelMapper, etc. With Mapstruct your mapper will look like:

@Mapper
public interface UserMapper {     
    UserMapper INSTANCE = Mappers.getMapper( UserMapper.class ); 

    UserDTO toDto(User user);
}

The real object with all getters and setters will be automatically generated from this interface. You can use it like:

UserDTO userDTO = UserMapper.INSTANCE.toDto(user);

You can also add some logic for your activeText filed using @AfterMapping annotation.


Wouldn't lambdaj's project function do what you are looking for?

It'll look something like this:

List<UserDTO> userNDtos = project(users, UserDTO.class, on(User.class).getUserName(), on(User.class).getFullName(), .....);

(Define the constructor for UserDTO accordingly...)

Also see here for examples...


You can use Apache Commmons Beanutils. The API is

org.apache.commons.beanutils.PropertyUtilsBean.copyProperties(Object dest, Object orig).

It copies property values from the "origin" bean to the "destination" bean for all cases where the property names are the same.

Now I am going to off topic. Using DTO is mostly considered an anti-pattern in EJB3. If your DTO and your domain objects are very alike, there is really no need to duplicate codes. DTO still has merits, especially for saving network bandwidth when remote access is involved. I do not have details about your application architecture, but if the layers you talked about are logical layers and does not cross network, I do not see the need for DTO.