androidentity什么用_android中Bean(Entity)间转换

本文介绍了在Android开发中如何利用注解和反射实现Entity之间的转换,以解决接口返回的数据结构与现有控件耦合的问题。通过定义MapProperty注解,并编写AnnotationUtils工具类,可以方便地将一个Entity转换为另一个Entity,适用于简单的单层和多层属性映射。但这种方法对于多层次、层级不对称的转换可能不够适用。
摘要由CSDN通过智能技术生成

问题描述:

之前的项目中,遇到一个问题,描述如下:

接口A请求结果转换后的EntityA与控件有高度耦合,控件大部分功能由EntityA的各属性来控制(这个看起来没有问题,虽然控件和业务逻辑最好能够分开,但是大部分情况下仍然很难做到);

有一个新需求,服务端提供了一个接口B,与接口A十分相似,并且希望能够复用原有的控件。

在大部分情况下不会遇到这种情况,但是当有多个后端团队提供支持的时候,便有可能出现(譬如参数规范到底是驼峰式还是下划线?)。

在java开发中,有很多Bean(Entity)间转换的工具,大部分采用了XML映射的方式。这种方式在服务端开发可能会更方便一些,但是在android开发中,对XML的属性文件支持不够(对XML属性文件的处理并不是很在行)。那么有没有对android更方便的Entity间转换方案呢?

实现方案:

基于java中注解和反射的使用,笔者编写如下一个工具类,可以实现android平台上entity间的转换,下面介绍这个工具。

编写annotation与annotationHandler

1. 首先,声明一个annotation。若EntityA要映射到EntityB的话,那么对EntityA中需要映射的属性,进行mapClass和mapProperty注解。

对于单层Entity(Entity中属性均为基本类型或者String),只需要使用mapProperty即可。

若为多层Entity(Entity中含有自定义的Entity属性),不仅需要使用mapProperty来设置对应的属性名,也需要mapClass来设置对应的类名了。

代码如下所示:

/*** 属性间的1:1映射关系

*

* Created by puff on 15/7/31.*/@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)public @interfaceMapProperty {public String mapClass() default "";public String mapProperty() default "";

}

2. 然后,我们再写一个annotation-handler,如果不对annotation做处理的话,那就没什么意义了。

工具类中第一个参数为源entity,第二个参数为目标entity类,换句话说我们把一个srcObj转到desObj,就需要有源obj和目标obj类两个参数。

首先若是列表类型,则对列表做处理(json转换过来的entity很多都是有列表的)。因为列表(和数组类似)这种属性比较特殊,不是自定义Entity也不属于基本类型,我们需要做的就是遍历列表,把item挨个进行转换。

其次,我们需要转换的无非就是一些基本类型和自定义类型了。备注写的比较详细,生成一个目标obj对象,通过反射检测源obj属性是否需要映射。不需要映射则直接pass(目标obj根本不需要这个属性)。若需要映射且是基本类型则直接取值并set进目标obj,若需要映射却是自定义类型则先递归处理再将结果set进去。

代码如下:

1 /**2 * Created by puff on 15/7/31.

3*/

4 public classAnnotationUtils {5 /**6 * *

7 * 将源entity转为目标entity依赖于MapProperty

8 *

9 *@paramobj 源entity

10 *@paramc 目标entity类

11 *@return目标entity

12 *@throwsException 反射处理annotation的异常

13*/

14 public static Object transformEntity(Object obj, Class c) throwsException {15 if (obj == null || c == null) {16 return null;17}18 if (obj instanceofList) {19 //列表单独处理

20 List src =(List) obj;21 List result = newLinkedList();22 for(Object item : src) {23result.add(transformEntity(item, c));24}25 returnresult;26 } else{27 //创建目标entity,待填充

28 Object result =c.newInstance();29 Field[] declaredFields =obj.getClass().getDeclaredFields();30 for(Field field : declaredFields) {31 //源属性开放属性权限

32 field.setAccessible(true);33 if (field.isAnnotationPresent(MapProperty.class)) {34 //获取源属性的映射注解

35 MapProperty annotation = field.getAnnotation(MapProperty.class);36 Object value =field.get(obj);37 if (!TextUtils.isEmpty(annotation.mapClass())) {38 //复杂属性,递归处理

39 value =transformEntity(value, Class.forName(annotation.mapClass()));40}41 Field resultField =c.getDeclaredField(annotation.mapProperty());42 resultField.setAccessible(true);43resultField.set(result, value);44}45}46 returnresult;47}48}49

50 }

例子(将EntityA转为EntityB)

1 /**2 *

3 *@authorpuff

4*/

5 public classEntityA {6

7 @MapProperty(mapProperty = "value_1")8 privateString value1;9 @MapProperty(mapProperty = "value_2", mapClass = "javaannotation.EntityB2")10 private List>value2;11

12 publicString getValue1() {13 returnvalue1;14}15

16 public voidsetValue1(String value1) {17 this.value1 =value1;18}19

20 public List>getValue2() {21 returnvalue2;22}23

24 public void setValue2(List>value2) {25 this.value2 =value2;26}27

28}29

30 /**31 *

32 *@authorpuff

33*/

34 public classEntityB {35

36 privateString value_1;37 private List>value_2;38

39 publicString getValue_1() {40 returnvalue_1;41}42

43 public voidsetValue_1(String value_1) {44 this.value_1 =value_1;45}46

47 public List>getValue_2() {48 returnvalue_2;49}50

51 public void setValue_2(List>value_2) {52 this.value_2 =value_2;53}54

55}56

57 public static void main(String[] args) throwsException {58 EntityA entityA =getEntityA();59 Object object = transformEntity(entityA, EntityB.class);60 if (!(object instanceofEntityB)) {61 System.out.println("error1");62}63 EntityB entityB =(EntityB) object;64 System.out.println("succ1");65 }

局限性:

因为后端的A,B接口基本上是一致的,如上的实现方法确实解决了笔者遇到的问题。

但对于多层次Entity的情况来说,有可能出现层级不对称的问题:譬如要把一个boolean转化为自定义类的某个变量上,或当一个自定义类的某个变量转化为一个boolean的情况下,使用如上实现方法并不能解决问题。如果真的遇到了这种情况,并且该情况出现的比较少,则可以考虑单独取值后set。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值