在微服务架构的项目中,我们经常会遇到外观模式设计,把核心的数据结构隐藏起来,暴露对外的request和response数据结构。如果嵌套的层级多了,层层的数据转换将会增加大量代码,让整个项目看起来臃肿不堪。例如:
public void saveVisitStatInfo(VisitStatRequest visitStatRequest) {
VisitStatPO visitStatPO = new VisitStatPO();
if(visitStatRequest != null) {
visitStatPO.setMemberId(visitStatRequest.getMemberId());
visitStatPO.setIpAddress(visitStatRequest.getIpAddress());
visitStatPO.setUtmCampaign(visitStatRequest.getUtmCampaign());
visitStatPO.setUtmContent(visitStatRequest.getUtmContent());
visitStatPO.setUtmMedium(visitStatRequest.getUtmMedium());
visitStatPO.setUtmSource(visitStatRequest.getUtmSource());
visitStatPO.setUtmTerm(visitStatRequest.getUtmTerm());
visitStatService.saveVisit(visitStatPO);
} else {
logger.error("Visit stat input is null");
}
}
因此我们可以找一个对象与对象之间的转换工具,完成统一转换。
关于java对象与对象之间的转换,可行的方式有以下几种
1、org.apache.commons.beanutils.PropertyUtils.copyProperties()方法
2、org.springframework.beans.BeanUtils.copyProperties(source, target)方法
3、利用json做中转转换
4、利用反射机制写一个对象转换工具
第1和第2种都不推荐使用,因为第1种的性能较差,不支持Date等类型。第2种不支持Integer,Long,Boolean等为null的传递,而且对于同名不同类型的数据转换会直接报错(网上有说只是不赋值,博主用JDK1.7亲测会报错如下)
org.springframework.beans.FatalBeanException: Could not copy properties from source to target; nested exception is java.lang.IllegalArgumentException: argument type mismatch
at org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java:620)
at org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java:530)
at test.main.main.test(main.java:119)
第3种推荐在没什么特殊需求的情况下使用,好处是深克隆,不担心地址污染,而且代码也简单。
第4种则推荐当转换过程中对赋值有特定要求的情况下使用。好处是支持所有类型和数据,而且可以自由定义转换过程中的数据处理方式。代码如下:
public static Object objToObj(Object source, Class<?> targetClazz) throws InstantiationException, IllegalAccessException {
Object target = targetClazz.newInstance();
Class sourceClazz = source.getClass();
Field[] sourceFields = sourceClazz.getDeclaredFields();
Field[] targetFields = target.getClass().getDeclaredFields();
for (Field sourceField : sourceFields) {
sourceField.setAccessible(true);
for (Field targetField : targetFields) {
if(targetField.getName().equals(sourceField.getName()) && targetField.getType() == sourceField.getType()) {
int mod = targetField.getModifiers();
if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
targetField.setAccessible(true);
targetField.set(target, sourceField.get(source));
break;
}
}
}
return target;
}
该段代码主要实现的是只有成员变量名称和类型都一致才赋值的浅克隆对象转换。有兴趣的同学可以通过修改判定条件实现不同的数据转换功能,也可以添加递归算法实现深克隆转换。
最后需要说明的是,无论选择哪种对象转换功能,都一定比直接通过set方法赋值效率要低,如何选择需要同学们自己把控。