2013-02-27 14 views
35

Nell'architettura della mia applicazione di solito invio l'oggetto o l'elenco di oggetti dal livello di accesso ai dati al livello Web tramite il livello di servizio, in cui questi oggetti vengono trasformati da DAO oggetto a un oggetto DTO e viceversa. Il livello Web non ha accesso agli oggetti DAO e il livello DAO non utilizza DTO.Modello DTO: il modo migliore per copiare le proprietà tra due oggetti

Per dimostrare, io di solito scrivo il codice come:

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

Qui l'utente è l'entità del database:

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

E questo è l'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; 
    } 
} 

Così Mi stavo chiedendo se questo è l'unico modo per copiare le proprietà tra due oggetti. Immagino di non essere sicuro. Inoltre sto usando lambdaj, quindi c'è un metodo in questa API da cui posso copiare tutte queste proprietà per creare una lista di altri oggetti?

Questo argomento può sembrare soggettivo, ma desidero davvero sapere da voi esperti i modi in cui è possibile eseguire la trasformazione dell'oggetto da una forma all'altra in cui i campi massimi hanno la stessa stringa.

+0

Possibile duplicato (https://stackoverflow.com/questions/1432764/any-tool- for-java-object-to-object-mapping) – tkruse

risposta

19

Si può avere uno sguardo a dozer che è un

Java Bean a Java Bean mapper che ricorsivamente copia i dati da un oggetto all'altro. In genere, questi Java Beans saranno di tipi diversi e complessi.

Another better link...

2

È possibile utilizzare la reflection per trovare tutti i metodi get nel DAO oggetti e chiamare il set metodo equivalente nel DTO. Questo funzionerà solo se esistono tutti questi metodi. Dovrebbe essere facile trovare un codice di esempio per questo.

22

È possibile utilizzare Apache Commmons Beanutils. L'API è

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

Copia i valori delle proprietà dal bean "origine" al bean "destinazione" per tutti i casi in cui i nomi delle proprietà sono uguali.

Ora sto andando fuori tema. L'uso di DTO è per lo più considerato un anti-pattern in EJB3. Se il tuo DTO e gli oggetti del dominio sono molto simili, non c'è davvero bisogno di duplicare i codici. DTO ha ancora dei meriti, soprattutto per il risparmio della larghezza di banda della rete quando si tratta di un accesso remoto. Non ho dettagli sulla tua architettura dell'applicazione, ma se i livelli di cui hai parlato sono livelli logici e non attraversano la rete, non vedo la necessità di DTO.

+14

Vero, questo è un anti-pattern in terra EJB. Ma nel nuovo mondo degli smart client (cioè il lato client MVC) sta rapidamente diventando una necessità. Non vuoi trascinare l'intero grafico dell'oggetto sul lato client ma solo quello che ti serve davvero. Quindi un DTO. –

+0

Questo è un buon suggerimento. Ma cosa succede se il DTO ha solo 4 proprietà e l'oggetto reale ha 50 proprietà. Il mio caso, quando utilizzo le copyProperties come menzionato qui, sovrascrive l'oggetto reale con sole proprietà. Il resto delle 46 proprietà diventa nullo. È così che dovrebbe comportarsi? – HopeKing

2

Non sarebbe Lambdaj's project function fare ciò che stai cercando?

Sembrerà qualcosa di simile:

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

(Definire il costruttore per UserDTO di conseguenza ...)

anche vedere here per esempi ...

4

ho avuto un'applicazione che avevo bisogno di convertire da un JPA entità DTO, e ho pensato e alla fine si avvicinò usando org.springframework.beans.BeanUtils.copyProperties per la copia di proprietà semplici e anche estensione e utilizzo di org.springframework.binding.convert.service.DefaultConversionService per la conversione di proprietà complesse.

In dettaglio il mio servizio è stato qualcosa di simile: [? Qualsiasi strumento per oggetto Java di opporsi mappatura]

@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); 
    } 
} 
Problemi correlati