BeanUtils对象与对象关系映射的源码学习和优化
所需代码:commons-beanutils-1.7.0-sources.jar
背景:
数据入参vo对象映射到数据库bo对象的属性值的映射,出现了问题,所使用的jar包为apache commons-beanutils的commons-beanutils-1.7.0.jar(不是Spring)使用的方法为BeanUtils.copyProperties(dest, src );
问题:
当入参vo的String shopId的值为null的时候,使用BeanUtils.copyProperties(dest, src );后,bo中的String shopId值变成了"",然而入库的update的sql的限制条件为,导致insert的sql中原有数据被覆盖。
方案:
方案一:
修改apache commons-beanutils的源码
方案二:
修改mapper.xml中的代码限制条件改为
目标:
修改现有生成代码,从根源上限制vo属性为null的时候,导致bo为""的问题。
解决方案:
这里采用方案一的方式:
下载apache commons-beanutils的源码,使用ide中的source下载。
说明:
commons-beanutils-1.7.0.jar为maven项目中编译执行的class文件
commons-beanutils-1.7.0-sources.jar为maven项目中可查看的java文件
原有代码:
BeanUtils
public static void copyProperties(Object dest, Object orig)
throws IllegalAccessException, InvocationTargetException {
BeanUtilsBean.getInstance().copyProperties(dest, orig);
}
BeanUtilsBean
public void copyProperties(Object dest, Object orig)
throws IllegalAccessException, InvocationTargetException {
// Validate existence of the specified beans
if (dest == null) {
throw new IllegalArgumentException
("No destination bean specified");
}
if (orig == null) {
throw new IllegalArgumentException("No origin bean specified");
}
if (log.isDebugEnabled()) {
log.debug("BeanUtils.copyProperties(" + dest + ", " +
orig + ")");
}
// Copy the properties, converting as necessary
if (orig instanceof DynaBean) {
DynaProperty origDescriptors[] =
((DynaBean) orig).getDynaClass().getDynaProperties();
for (int i = 0; i < origDescriptors.length; i++) {
String name = origDescriptors[i].getName();
if (getPropertyUtils().isWriteable(dest, name)) {
Object value = ((DynaBean) orig).get(name);
copyProperty(dest, name, value);
}
}
} else if (orig instanceof Map) {
Iterator names = ((Map) orig).keySet().iterator();
while (names.hasNext()) {
String name = (String) names.next();
if (getPropertyUtils().isWriteable(dest, name)) {
Object value = ((Map) orig).get(name);
copyProperty(dest, name, value);
}
}
} else /* if (orig is a standard JavaBean) */ {
PropertyDescriptor origDescriptors[] =
getPropertyUtils().getPropertyDescriptors(orig);
for (int i = 0; i < origDescriptors.length; i++) {
String name = origDescriptors[i].getName();
if ("class".equals(name)) {
continue; // No point in trying to set an object's class
}
if (getPropertyUtils().isReadable(orig, name) &&
getPropertyUtils().isWriteable(dest, name)) {
try {
Object value =
getPropertyUtils().getSimpleProperty(orig, name);
copyProperty(dest, name, value);
} catch (NoSuchMethodException e) {
; // Should not happen
}
}
}
}
}
上面代码为原有代码,如何理解,通过反射的方式,获取属性名,然后通过属性名相同的equals()判断是否相同,然后再复制copyProperty(dest, name, value);
Object dest映射后的类,Object orig映射前的类,name是属性名,value是属性的值
思考:
value是属性的值,那么判断value==null是否成立,然后成立不赋值,不成立将属性赋值
修改代码:
新建一个空白的maven项目(什么项目都可以)
从commons-beanutils-1.7.0-sources.jar中将BeanUtils.java和BeanUtilsBean.java复制过来(包名和原来一致)
maven项目中映入依赖commons-beanutils-1.7.0和commons-logging-1.1,不引入commons-logging-1.1,BeanUtilsBean.java汇报错,java文件找不到
BeanUtils.java
public static void copyProperties(Object dest, Object orig ,boolean inNull)
throws IllegalAccessException, InvocationTargetException {
BeanUtilsBean.getInstance().copyProperties(dest, orig , inNull);
}
新写入一个copyProperties方法,Object dest映射后对象,Object orig映射前对象,boolean inNull是否处理空对象,true(orig属性为空,dest属性为空),false(orig属性为空,dest属性为"")
BeanUtilsBean.java
public void copyProperties(Object dest, Object orig ,boolean isNull)
throws IllegalAccessException, InvocationTargetException {
// Validate existence of the specified beans
if (dest == null) {
throw new IllegalArgumentException
("No destination bean specified");
}
if (orig == null) {
throw new IllegalArgumentException("No origin bean specified");
}
if (log.isDebugEnabled()) {
log.debug("BeanUtils.copyProperties(" + dest + ", " +
orig + ")");
}
// Copy the properties, converting as necessary
if (orig instanceof DynaBean) {
DynaProperty origDescriptors[] =
((DynaBean) orig).getDynaClass().getDynaProperties();
for (int i = 0; i < origDescriptors.length; i++) {
String name = origDescriptors[i].getName();
if (getPropertyUtils().isWriteable(dest, name)) {
Object value = ((DynaBean) orig).get(name);
copyProperty(dest, name, value);
}
}
} else if (orig instanceof Map) {
Iterator names = ((Map) orig).keySet().iterator();
while (names.hasNext()) {
String name = (String) names.next();
if (getPropertyUtils().isWriteable(dest, name)) {
Object value = ((Map) orig).get(name);
copyProperty(dest, name, value);
}
}
} else /* if (orig is a standard JavaBean) */ {
PropertyDescriptor origDescriptors[] =
getPropertyUtils().getPropertyDescriptors(orig);
for (int i = 0; i < origDescriptors.length; i++) {
String name = origDescriptors[i].getName();
if ("class".equals(name)) {
continue; // No point in trying to set an object's class
}
if (getPropertyUtils().isReadable(orig, name) &&
getPropertyUtils().isWriteable(dest, name)) {
try {
Object value =
getPropertyUtils().getSimpleProperty(orig, name);
//不同的地方
if (isNull){
//isNull为true
if (value==null) {
//value为null,不进行赋值操作
continue;
} else {
copyProperty(dest, name, value);
}
}else {
copyProperty(dest, name, value);
}
} catch (NoSuchMethodException e) {
; // Should not happen
}
}
}
}
}
编译代码修改jar包:
将编译后的BeanUtils.class和BeanUtilsBean.class复制到commons-beanutils-1.7.0.jar的指定包位置
代码运行执行就是新代码了
若idea报Library source does not match the bytecode for class这个错误
原因:idea自动反编译commons-beanutils-1.7.0.jar的代码,发现与commons-beanutils-1.7.0-sources.jar中的源码不同
解决方案:把BeanUtils.java和BeanUtilsBean.java复制到commons-beanutils-1.7.0-sources.jar的指定包位置
然后将idea中的缓存清除一下重新载入即可。
拿下拿下,完美收工!