2013-02-27 5 views
35

In der Architektur meiner Anwendung sende ich normalerweise das Objekt oder die Objektliste von der Datenzugriffsebene über die Serviceschicht zur Webschicht, in der diese Objekte von einer DAO transformiert werden Objekt zu einem DTO Objekt und umgekehrt. Die Webebene hat keinen Zugriff auf DAO-Objekte und die DAO-Ebene verwendet keine DTOs.DTO-Muster: Die beste Methode zum Kopieren von Eigenschaften zwischen zwei Objekten

Um zu demonstrieren, ich in der Regel den Code schreiben wie:

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

Hier kann der Benutzer die Datenbankeinheit:

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

Und das ist die 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 Ich frage mich, ob das die einzige Möglichkeit ist, Eigenschaften zwischen zwei Objekten zu kopieren. Ich bin mir nicht sicher. Auch verwende ich lambdaj, so gibt es eine Methode in dieser API, mit der ich alle diese Eigenschaften kopieren kann, um eine Liste anderer Objekte zu erstellen?

Dieses Thema klingt vielleicht subjektiv, aber ich möchte wirklich von Ihnen Experten wissen, wie die Transformation eines Objekts von einer Form zur anderen erfolgen kann, wo die maximalen Felder die gleiche Zeichenfolge haben.

+0

Mögliches Duplikat (https://stackoverflow.com/questions/1432764/any-tool- for-java-object-to-object-mapping) – tkruse

Antwort

19

Sie können einen Blick auf dozer haben, die ein

Java Bean zu Java Bean Mapper, die rekursiv kopiert Daten von einem Objekt zum anderen

ist. In der Regel werden diese Java Beans unterschiedlich komplex sein.

Another better link...

2

Sie können Reflektion verwenden, um alle get Methoden in Ihrem DAO Objekte und rufen Sie das Äquivalent set Methode in der DTO zu finden. Dies funktioniert nur, wenn alle diese Methoden existieren. Es sollte einfach sein, Beispielcode dafür zu finden.

22

können Sie Apache Commmons Beanutils verwenden. Die API ist

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

Es kopiert Eigenschaftswerte von der "Ursprungs" -Bohne in die "Ziel" -Bohne für alle Fälle, in denen die Eigenschaftsnamen identisch sind.

Jetzt gehe ich zum Thema. Die Verwendung von DTO wird in EJB3 meist als Anti-Pattern betrachtet. Wenn Ihr DTO und Ihre Domänenobjekte sehr ähnlich sind, müssen Codes nicht wirklich dupliziert werden. DTO hat immer noch Vorteile, insbesondere zum Speichern der Netzwerkbandbreite bei Remote-Zugriffen. Ich habe keine Details zu Ihrer Anwendungsarchitektur, aber wenn die Ebenen, über die Sie gesprochen haben, logische Schichten sind und kein Netzwerk kreuzen, sehe ich keinen Bedarf für DTO.

+14

Richtig, dies ist ein Anti-Pattern im EJB-Land. Aber in der neuen Smart-Client-Welt (d. H. Client-Seite MVC) wird es schnell zu einer Notwendigkeit. Sie möchten nicht Ihr gesamtes Objektdiagramm auf die Client-Seite ziehen, sondern nur das, was Sie dort wirklich brauchen. Daher ein DTO. –

+0

Dies ist ein guter Vorschlag. Aber was, wenn der DTO nur 4 Eigenschaften hat und das tatsächliche Objekt 50 Eigenschaften hat. Wenn ich die copyProperties wie hier erwähnt benutze, überschreibt es das tatsächliche Objekt mit nur den Eigenschaften. Der Rest der 46 Eigenschaften wird null. Soll es sich so verhalten? – HopeKing

2

Würde nicht lambdajs project function tun, was Sie suchen?

Es wird in etwa so aussehen:

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

(Definieren Sie den Konstruktor für UserDTO entsprechend ...)

Auch here Beispiele siehe ...

4

ich eine Anwendung hatte, die ich von einer JPA Einheit DTO zu konvertieren benötigt, und ich dachte darüber nach und kam schließlich org.springframework.beans.BeanUtils.copyProperties zum Kopieren von einfachen Eigenschaften mit und auch Erweiterung und Verwendung org.springframework.binding.convert.service.DefaultConversionService für die Konvertierung komplexer Eigenschaften.

Im Detail meines Service war so etwas wie diese: [? Jedes Werkzeug für Java-Objekt Objekt Mapping]

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