属性转换工具Apache BeanUtils, Spring BeanUtils, cglib BeanCopier
由于历史原因,项目中用到大量common-beanutils中的BeanUtils.copyProperties
顺便研究一下属性复制,主流的属性拷贝有
apache 的org.apache.commons.beanutils.BeanUtils
public static void copyProperties(Object dest, Object orig)
spring的org.springframework.beans.BeanUtils
public static void copyProperties(Object source, Object target)
cg-lib的net.sf.cglib.beans.BeanCopier
public abstract void copy(Object src, Object dest, Converter var3)
需要注意:
apache的第一个参数是目标对象,第二个参数是源对象,
Spring和cglib第一个参数是源对象,第二个是目标对象
遇到的问题
1. common-beanutils和Spring beanutils都用到了反射
性能上cg-lib>spring>apache, 我是直接从apache切换到cglib, 所以我没有尝试spring,
common-beanutils版本是1.7.2, cglib版本是2.1
2. 切换后报NullPointException,是因为目标对象中的某个属性只有get方法,没有set方法,解决方案是cglib升级到3.3
3. 报错java.lang.ClassCastException: java.lang.String incompatible with java.math.BigDecimal
有的将BigDecimal转换为String,这个我可以理解,还有将String转换为BigDecimal,这个太坑了
解决方法,自己写一个converter吧
public class BeanCopierUtil {
private BeanCopierUtil() {
}
private static final Map<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();
public static void copyProperties( Object target,Object source) {
String beanKey = generateKey(source.getClass(), target.getClass());
BeanCopier copier = null;
if (!BEAN_COPIER_CACHE.containsKey(beanKey)) {
copier = BeanCopier.create(source.getClass(), target.getClass(), true);
BEAN_COPIER_CACHE.put(beanKey, copier);
} else {
copier = BEAN_COPIER_CACHE.get(beanKey);
}
BeanCopyConverter converter = new BeanCopyConverter();
copier.copy(source,target,converter);
}
private static String generateKey(Class<?> srcClazz, Class<?> destClazz){
return srcClazz.getName()+destClazz.getName();
}
}
class BeanCopyConverter implements Converter {
private Log logger = LogFactory.getLog(BeanCopyConverter.class);
@SuppressWarnings("rawtypes")
@Override
public Object convert(Object source, Class target, Object context) {
try{
if (source instanceof Integer) {
if(target.getName().equals("java.lang.String") )
return ((Integer) source).toString();
}else if (source instanceof BigDecimal) {
if(target.getName().equals("java.lang.String") )
return ((BigDecimal) source).toString();
}else if (source instanceof String) {
if(target.getName().equals("java.math.BigDecimal") )
return new BigDecimal((String) source);
}
}catch (Exception ex){
logger.warn("Error in convert value "+source.toString() +" to "+target.getName());
}
return source;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异