DTO pattern: meilleure façon de copier les propriétés entre deux objets

dans l'architecture de mon application j'envoie habituellement l'objet ou la liste des objets de la couche d'accès aux données à la couche web via la couche service, dans laquelle ces objets se transforment d'un DAO objet DTO objet et vice versa. La couche web n'a pas accès aux objets DAO et la couche DAO n'utilise pas de DTOs.

Pour le démontrer, j'ai l'habitude d'écrire le code:

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

ici l'utilisateur est la base de données entité:

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

Et c'est la 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;
    }
}

alors je me demandais si c'était la seule façon de copier des propriétés entre deux objets. Je suppose que je ne suis pas sûr. Aussi, je suis à l'aide de lambdaj, donc y a-t-il une méthode dans cette API par laquelle je peux copier toutes ces propriétés pour créer une liste d'autres objets?

ce sujet peut sembler subjectif, mais je veux vraiment savoir de vos experts les façons dont la transformation d'un objet d'un form to another peut être fait là où les champs maximum ont la même chaîne.

38
demandé sur Peter Mortensen 2013-02-27 20:39:08

6 réponses

Vous pouvez avoir un coup d'oeil à bull est un

Java Bean to Java Bean mapper qui copie récursivement des données d'un objet à un autre. Typiquement, ces grains de Java seront de différents types complexes.

un autre meilleur lien...

21
répondu pgras 2013-02-27 16:45:19

Vous pouvez utiliser Apache Commmons Beanutils. L'API est

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

il copie les valeurs de propriété de la fève "origine" à la fève "destination" pour tous les cas où les noms de propriété sont les mêmes.

Maintenant, je vais hors sujet. L'utilisation de DTO est principalement considérée comme un modèle anti-patron dans EJB3. Si votre DTO et vos objets de domaine sont très semblables, il n'est vraiment pas nécessaire de dupliquer des codes. DTO a encore des avantages, surtout pour économiser bande passante du réseau lorsque l'accès à distance est impliqué. Je n'ai pas de détails sur votre architecture d'application, mais si les couches dont vous avez parlé sont des couches logiques et ne traversent pas le réseau, Je ne vois pas la nécessité de DTO.

24
répondu Lan 2013-03-02 05:37:57

j'avais une application que je devais convertir d'un JPA entité DTO, et je l'ai pensé et enfin est venu à l'aide de org.springframework.beans.BeanUtils.copyProperties pour copier des propriétés simples et aussi étendre et utiliser org.springframework.binding.convert.service.DefaultConversionService pour convertir des propriétés complexes.

En détail mon service était quelque chose comme ceci:

@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);
    }
}
4
répondu Reza 2017-09-03 15:01:23

ne Serait pas lambdaj fonction faites ce que vous recherchez?

Ça va ressembler à quelque chose comme ceci:

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

(définir le constructeur pour UserDTO en conséquence...)

voir Aussi ici pour des exemples...

2
répondu Ashkan Aryan 2017-09-03 15:00:16

Vous pouvez utiliser la réflexion pour trouver tous les get méthodes dans votre DAO objets et d'appeler l'équivalent set méthode DTO. Cela ne fonctionnera que si toutes ces méthodes existent. Il devrait être facile de trouver un exemple de code pour cela.

2
répondu Skip Head 2017-09-27 07:05:16
Mapstruct, ModelMapper, etc. Avec Mapstruct votre mapper va ressembler à ça:

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

    UserDTO toDto(User user);
}

l'objet réel avec tous les getters et setters sera généré automatiquement à partir de cette interface. Vous pouvez l'utiliser comme:

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

vous pouvez aussi ajouter de la logique pour votre activeText déposé en utilisant @AfterMapping annotation.

1
répondu Anton Orlov 2018-06-20 16:11:40