- 项目又做回了web端,遇到了一个之前听过问题
- 项目接口接受的对象为req对象,数据库使用的为dto对象,有大量名称相同的字段,需要进行类型转换。同名字段赋值
- 每一次都重复20多次的set方法显得很蠢,之前朋友说用反射方法 效率很低闲来无事实现了一下
package *.biz.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
*
* 将一个类型T的对象 相同属性赋值给 类型R的对象
* @author 16
*/
@Slf4j
public class TransformUtils<T,R> {
// publice <T,R> T
public static <T,R> R transform(T src, R dest) {
Class<?> srcClass = src.getClass();
Field[] srcFields = srcClass.getDeclaredFields();
Class<?> destClass = dest.getClass();
Field[] destFields = destClass.getDeclaredFields();
Object o;
destClass.getDeclaredFields();
// 遍历src的属性 如果不为null
for (Field f : srcFields) {
// 获取src的值
f.setAccessible(true);
Object fieldValue = null;
try {
fieldValue = f.get(src);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (fieldValue == null) {
log.info(f.getName() + "属性不存在忽略");
continue;
}
Method[] methods = destClass.getMethods();
// 就尝试赋值给dest
try {
String name = f.getName();
StringBuilder replaceName = new StringBuilder(name).replace(0, 1, String.valueOf(Character.toUpperCase(name.charAt(0))));
Method method = dest.getClass().getMethod("set" + replaceName, f.getType());
method.invoke(dest, fieldValue);
// 方法不存在会抛出异常 所以此处存在
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.info(f.getName() + "set方法不存在忽略");
continue;
}
log.info(f.getName() + " 替换为"+ fieldValue + " 成功");
}
return dest;
}
public static void main(String[] args) {
AppApplyReq appApplyReq = new AppApplyReq();
appApplyReq.setId(1234);
long startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
AppApplyDO appApplyDO = new AppApplyDO();
appApplyReq = transform(appApplyDO, appApplyReq);
log.info(appApplyDO.getId() + "");
log.info(appApplyReq.getId() + "");
log.info("usedTime=" + (System.nanoTime() - startTime));
}
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
AppApplyDO appApplyDO1 = appApplyReq.forAppApplyDo();
}
log.info("usedTime=" + (System.nanoTime() - startTime));
}
}
16:43:50.384 [main] INFO *.utils.TransformUtils - usedTime=4153631688
16:43:50.387 [main] INFO *.utils.TransformUtils - usedTime=3009321
-
如果没写bug的话 效率应该相差了1000倍
-
本来以为反射多次使用的话效率应该会有优化 实际测试过程中发现并没有
-
然后 为了偷懒 代码自动生成类
/**
*
* @param srcClass
* @param destClass
* @return
*/
public static String buildCode(Class<?> srcClass,Class<?> destClass) {
// Class<?> srcClass = src.getClass();
Field[] srcFields = srcClass.getDeclaredFields();
// Class<?> destClass = dest.getClass();
Field[] destFields = destClass.getDeclaredFields();
String srcClassName = srcClass.getSimpleName();
String destClassName = destClass.getSimpleName();
String srcObjectName = firstCharLower(srcClassName);
String destObjectName = firstCharLower(destClassName);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("public " + destClassName +" transform" + srcClassName + "2" + destClassName
+"(" + srcClassName + " " +srcObjectName +", " + destClassName + " " + destObjectName + "){\n");
for (Field f : srcFields) {
String fieldName = f.getName();
String upperFieldName = firstCharUpper(fieldName);
String srcGetMethodName = "get" + upperFieldName;
String destSetMethodName = "set" + upperFieldName;
try {
srcClass.getMethod(srcGetMethodName);
destClass.getMethod(destSetMethodName, f.getType());
stringBuilder
.append("\t")
.append(destObjectName)
.append(".")
.append(destSetMethodName)
.append("(")
.append(srcObjectName)
.append(".")
.append(srcGetMethodName)
.append("());\n");
} catch (NoSuchMethodException e) {
log.info(fieldName + "没有匹配的方法!");
}
log.info(fieldName + "匹配成功!");
}
stringBuilder.append("}\n");
System.out.println(stringBuilder.toString());
return stringBuilder.toString();
}
public static String firstCharUpper(String str) {
char[] chars = str.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return String.valueOf(chars);
}
public static String firstCharLower(String str) {
char[] chars = str.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return String.valueOf(chars);
}
自动生成的代码示例
public AppApplyDO transformAppApplyReq2AppApplyDO(AppApplyReq appApplyReq, AppApplyDO appApplyDO){
appApplyDO.setId(appApplyReq.getId());
appApplyDO.setOrgId(appApplyReq.getOrgId());
appApplyDO.setOrgCode(appApplyReq.getOrgCode());
appApplyDO.setOrgName(appApplyReq.getOrgName());
}