2013-02-27 9 views
35

私のアプリケーションのアーキテクチャでは、通常、オブジェクトまたはオブジェクトのリストをデータレイヤーからサービスレイヤーを介してWebレイヤーに送信します。これらのオブジェクトはDAOオブジェクトをDTOオブジェクトに、またはその逆にします。 WebレイヤーはDAOオブジェクトへのアクセス権を持たず、DAOレイヤーはDTOを使用しません。実証するためにDTOパターン:2つのオブジェクト間でプロパティをコピーする最良の方法

、私は通常のようにコードを記述します。ここでは

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

ユーザーは、データベース・エンティティである:

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

そして、これは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; 
    } 
} 

私は、これが2つのオブジェクト間でプロパティをコピーする唯一の方法であるかどうか疑問に思っていました。私は確信していないと思う。また、私はlambdajを使用していますので、このAPIにこれらのプロパティをすべてコピーして他のオブジェクトのリストを作成する方法がありますか?

このトピックは主観的に聞こえるかもしれませんが、私は、最大フィールドが同じ文字列を持つ場所で、あるフォームから別のフォームへのオブジェクトの変換を行う方法を専門家から知りたいと思っています。

+0

可能な複製(https://stackoverflow.com/questions/1432764/any-tool- for-java-object-to-object-mapping) – tkruse

答えて

19

あなたは、その別のオブジェクトから再帰的にデータをコピーしたJava Beanマッパーへ

あるdozer見たJava Beanの持つことができます。通常、これらのJava Beanは、複雑なタイプの異なるものになります。

Another better link...

2

あなたのDAOオブジェクト内のすべてのget方法を見つけて、DTOに同等のsetメソッドを呼び出すためにリフレクションを使用することができます。このようなメソッドがすべて存在する場合にのみ機能します。このためのサンプルコードを見つけるのは簡単です。

22

あなたはApache Commmons Beanutilsを使用することができます。 APIは

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

プロパティ名が同じであるすべてのケースで、 "origin" beanから "destination" beanにプロパティ値をコピーします。

今、私はトピックを外すつもりです。 DTOの使用は、主にEJB3のアンチパターンとみなされます。 DTOとドメインオブジェクトが非常に似ている場合は、コードを複製する必要はありません。 DTOには、特にリモートアクセスが関与している場合にネットワーク帯域幅を節約するためのメリットがあります。私はあなたのアプリケーションアーキテクチャーについて詳しくは言及していませんが、あなたが話したレイヤーが論理レイヤーでネットワークを越えていないのであれば、私はDTOの必要性は見当たりません。

+14

真、これはEJBランドの反パターンです。しかし、新しいスマートクライアントの世界(すなわち、クライアント側のMVC)では、それはすぐに必要になってきている。オブジェクトグラフ全体をクライアント側に引き渡すのではなく、そこに本当に必要なものだけを取り込もうとします。従って、DTO。 –

+0

これは良い提案です。 DTOに4つのプロパティしかなく、実際のオブジェクトに50のプロパティがある場合はどうでしょうか?私のケースでは、ここで述べたようにcopyPropertiesを使用すると、実際のオブジェクトによってプロパティのみで上書きされます。残りの46個のプロパティはnullになります。これはどのように動作すると予想されますか? – HopeKing

2

lambdajさんのproject functionさんへの返信です。

それはこのようなものを見てみましょう:

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

(従ってUserDTOのコンストラクタを定義し...)

また例についてhereを参照してください...

4

は私がDTOにJPAエンティティから変換するために必要なアプリケーションを持っていた、と私はそれについて考え、最終的にも単純なプロパティをコピーするためのorg.springframework.beans.BeanUtils.copyPropertiesを使用して上がってきました複合プロパティの変換にはorg.springframework.binding.convert.service.DefaultConversionServiceを拡張して使用します。具体的には

私のサービスは、このようなものでした:[?オブジェクトへのマッピングJavaオブジェクトのための任意のツール]の

@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); 
    } 
} 
関連する問題