Dozer轻松实现对象间属性复制

Dozer

 

对外接口,一般都使用特定的DTO对象,而不会使用领域模型,以避免两者的变动互相影响。其他框架适配等情形,也可能需要DTO对象。

 

如果手工一个个属性的在两个对象间复制有点累人,如果对象里面还有对象,就更累了。所以希望有一个工具类,可以一行代码就把对象A中的属性全部Copy到对象B中。 普通的反射框架不适合做这个事情,看看Dozer 所支持的特性就知道了:

 

支持两个对象间的同一属性的类型是异构的对象,比如CarDTOengine属性是EngineDTO Carengine属性是Engine

 

支持String <-> 基础类型的转换,比如CarDTOprice属性是String, Carprice属性是Double.

 

支持Collection类型间的转换,比如String[] <-> List

 

支持双向依赖,比如Product有个属性是List parts, 而每个Part也有一个Product属性,此时ProductPart双向依赖了。

 

属性名实在不一致时,可以用@Mapping定义,而且只在其中一边定义就可以了。

 

Dozer 也有个缺点,必须基于getter/setter,不能直接访问public field,卡住了我让Entity/DTO都取消掉getter/setter的计划。

 

Dozer已比较成熟,所以更新很慢。另一个类似但更新较勤快的项目叫Orika

 

 

In SpringSide

core中封装了一个BeanMapper,实现如下功能:

 

持有Dozer单例, 避免重复创建DozerMapper消耗资源.

 

自动泛型类型转换.

 

批量转换Collection中的所有对象.

 

区分创建新的B对象与将对象A值赋值到已存在的B对象的函数.

 

showcase中有一个DozerDemo,详细演示了Dozer上述的各种特性。

 

 

 

所需jar

 

 1<dependency>

         <groupId>net.sf.dozer</groupId>

         <artifactId>dozer</artifactId>

         <version>5.3.1</version>

      </dependency>

 2<dependency>

         <groupId>org.springside</groupId>

         <artifactId>springside-core</artifactId>

      </dependency>

  1 package org.springside.examples.showcase.utilities.dozer;
  2 
  3 import static org.junit.Assert.*;
  4 
  5 import java.util.List;
  6 
  7 import org.dozer.Mapping;
  8 import org.junit.Test;
  9 import org.springside.modules.mapper.BeanMapper;
 10 
 11 /**
 12  * 演示Dozer如何只要属性名相同,可以罔顾属性类型是基础类型<->String的差别,Array转为List,甚至完全另一种DTO的差别。
 13  * 并且能完美解决循环依赖问题。
 14  * 使用@Mapping能解决属性名不匹配的情况.
 15  */
 16 public class DozerDemo {
 17 
 18     /**
 19      * 从一个ProductDTO实例,创建出一个新的Product实例。
 20      */
 21     @Test
 22     public void map() {
 23         ProductDTO productDTO = new ProductDTO();
 24         productDTO.setName("car");
 25         productDTO.setPrice("200");
 26 
 27         PartDTO partDTO = new PartDTO();
 28         partDTO.setName("door");
 29         partDTO.setProduct(productDTO);
 30 
 31         productDTO.setParts(new PartDTO[] { partDTO });
 32 
 33         //ProductDTO->Product
 34         Product product = BeanMapper.map(productDTO, Product.class);
 35 
 36         assertEquals("car", product.getProductName());
 37         //原来的字符串被Map成Double。
 38         assertEquals(new Double(200), product.getPrice());
 39         //原来的PartDTO同样被Map成Part ,Array被Map成List
 40         assertEquals("door", product.getParts().get(0).getName());
 41         //Part中循环依赖的Product同样被赋值。
 42         assertEquals("car", product.getParts().get(0).getProduct().getProductName());
 43 
 44         //再反向从Product->ProductDTO
 45         ProductDTO productDTO2 = BeanMapper.map(product, ProductDTO.class);
 46         assertEquals("car", productDTO2.getName());
 47         assertEquals("200.0", productDTO2.getPrice());
 48         assertEquals("door", productDTO2.getParts()[0].getName());
 49     }
 50 
 51     /**
 52      * 演示将一个ProductDTO实例的内容,Copy到另一个已存在的Product实例.
 53      */
 54     @Test
 55     public void copy() {
 56         ProductDTO productDTO = new ProductDTO();
 57         productDTO.setName("car");
 58         productDTO.setPrice("200");
 59 
 60         PartDTO partDTO = new PartDTO();
 61         partDTO.setName("door");
 62         partDTO.setProduct(productDTO);
 63 
 64         productDTO.setParts(new PartDTO[] { partDTO });
 65 
 66         //已存在的Product实例
 67         Product product = new Product();
 68         product.setProductName("horse");
 69         product.setWeight(new Double(20));
 70 
 71         BeanMapper.copy(productDTO, product);
 72 
 73         //原来的horse,被替换成car
 74         assertEquals("car", product.getProductName());
 75         //原来的20的属性被覆盖成200,同样被从字符串被专为Double。
 76         assertEquals(new Double(200), product.getPrice());
 77         //DTO中没有的属性值,在Product中被保留
 78         assertEquals(new Double(20), product.getWeight());
 79         //Part中循环依赖的Product同样被赋值。
 80         assertEquals("car", product.getParts().get(0).getProduct().getProductName());
 81     }
 82 
 83     public static class Product {
 84         private String productName;
 85         private Double price;
 86         private List<Part> parts;
 87         //DTO中没有的属性
 88         private Double weight;
 89 
 90         public String getProductName() {
 91             return productName;
 92         }
 93 
 94         public void setProductName(String productName) {
 95             this.productName = productName;
 96         }
 97 
 98         public Double getPrice() {
 99             return price;
100         }
101 
102         public void setPrice(Double price) {
103             this.price = price;
104         }
105 
106         public List<Part> getParts() {
107             return parts;
108         }
109 
110         public void setParts(List<Part> parts) {
111             this.parts = parts;
112         }
113 
114         public Double getWeight() {
115             return weight;
116         }
117 
118         public void setWeight(Double weight) {
119             this.weight = weight;
120         }
121 
122     }
123 
124     public static class Part {
125         //反向依赖Product
126         private Product product;
127 
128         private String name;
129 
130         public String getName() {
131             return name;
132         }
133 
134         public void setName(String name) {
135             this.name = name;
136         }
137 
138         public Product getProduct() {
139             return product;
140         }
141 
142         public void setProduct(Product product) {
143             this.product = product;
144         }
145     }
146 
147     public static class ProductDTO {
148         //定义到Product中的productName,只要在一边定义,双向转换都可以使用.
149         @Mapping("productName")
150         private String name;
151         //类型为String 而非 Double
152         private String price;
153         //类型为Array而非List, PartDTO而非Part
154         private PartDTO[] parts;
155 
156         public String getName() {
157             return name;
158         }
159 
160         public void setName(String name) {
161             this.name = name;
162         }
163 
164         public String getPrice() {
165             return price;
166         }
167 
168         public void setPrice(String price) {
169             this.price = price;
170         }
171 
172         public PartDTO[] getParts() {
173             return parts;
174         }
175 
176         public void setParts(PartDTO[] parts) {
177             this.parts = parts;
178         }
179     }
180 
181     public static class PartDTO {
182         //反向依赖ProductDTO
183         private ProductDTO product;
184 
185         private String name;
186 
187         public String getName() {
188             return name;
189         }
190 
191         public void setName(String name) {
192             this.name = name;
193         }
194 
195         public ProductDTO getProduct() {
196             return product;
197         }
198 
199         public void setProduct(ProductDTO product) {
200             this.product = product;
201         }
202 
203     }
204 
205 }
206 

 

posted on 2012-09-07 11:03 Nirvana reborn 阅读(10420) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2012年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

导航

统计

公告

我好喜欢它,
我的 QQ 66013804
我想做技术流,可是我很懒,
博客新地址:<a href="http://cobaya.cn/" >

随笔分类(19)

文章档案(1)

博主链接

最新评论

阅读排行榜