这两天碰到了一个令人头秃的问题,花费了我一整天的时间最终跟踪到了问题根源:

    @Testpublic void testOrderPage(){Page page = new Page();Pagination pagination = new Pagination(2,5);try {// 这里copy时,pagination中的current(2)和size(5)并没有copy到page对象PropertyUtils.copyProperties(page, pagination);} catch (Exception e) {e.printStackTrace();}}
public class Page {// ...protected long current = 1;// ...public long getCurrent() {return this.current;}// 根源就是在这里的set方法返回值不是voidpublic Page setCurrent(long current) {this.current = current;return this;}// ...
}public class Pagination {// ...public Pagination(long current, long size) {if (current > 1) {this.current = current;}this.size = size;}// ...private long size = 10;private long current = 1;// ...public long getSize() {return size;}// ...public void setSize(long size) {this.size = size;}// ...public long getCurrent() {return current;}public void setCurrent(int current) {this.current = current;}
}

一路跟踪下去

org\apache\commons\beanutils\PropertyUtils.java

public static void copyProperties(final Object dest, final Object orig){PropertyUtilsBean.getInstance().copyProperties(dest, orig);
}

org\apache\commons\beanutils\PropertyUtilsBean.java

public void copyProperties(final Object dest, final Object orig){if (...) {// ...} else /* if (orig is a standard JavaBean) */ {final PropertyDescriptor[] origDescriptors = getPropertyDescriptors(orig);for (PropertyDescriptor origDescriptor : origDescriptors) {final String name = origDescriptor.getName();// 跟踪到这里的isWriteable,是判断目标对象的name属性是否可写if (isReadable(orig, name) && isWriteable(dest, name)) {// ...}}}
}public boolean isWriteable(Object bean, String name) {// ...// 为null的原因在这里 ↓final PropertyDescriptor desc = getPropertyDescriptor(bean, name);if (desc != null) {// 这里应该拿到目标对象属性的set方法,但是为null,见上面 ↑Method writeMethod = getWriteMethod(bean.getClass(), desc);if (writeMethod == null) {// ...}return (writeMethod != null);} else {return (false);}
}public PropertyDescriptor getPropertyDescriptor(Object bean, String name){// ...// 通过BeanIntrospectionData 对象的 getDescriptor 获取属性描述对象final BeanIntrospectionData data = getIntrospectionData(bean.getClass());PropertyDescriptor result = data.getDescriptor(name);// ...return result;
}private BeanIntrospectionData getIntrospectionData(final Class<?> beanClass) {// ...// 这里还用了个缓存 descriptorsCache,通过 beanClass 获取 BeanIntrospectionData 对象BeanIntrospectionData data = descriptorsCache.get(beanClass);if (data == null) {data = fetchIntrospectionData(beanClass);descriptorsCache.put(beanClass, data);}return data;
}private BeanIntrospectionData fetchIntrospectionData(final Class<?> beanClass) {final DefaultIntrospectionContext ictx = new DefaultIntrospectionContext(beanClass);for (final BeanIntrospector bi : introspectors) {try {// 这里就是处理获取 PropertyDescriptors 的地方,然后追踪到 org.apache.commons.beanutils.DefaultBeanIntrospector#introspectbi.introspect(ictx);} catch (final IntrospectionException iex) {log.error("Exception during introspection", iex);}}// 这里会把处理后的 PropertyDescriptors 设置到 BeanIntrospectionData 里并返回return new BeanIntrospectionData(ictx.getPropertyDescriptors());
}

org\apache\commons\beanutils\DefaultBeanIntrospector.java

public void introspect(final IntrospectionContext icontext) {// 通过 jdk 的 Introspector.getBeanInfo -> beanInfo.getPropertyDescriptors() 获取 PropertyDescriptor[]BeanInfo beanInfo = null;try {beanInfo = Introspector.getBeanInfo(icontext.getTargetClass());} catch (final IntrospectionException e) { //... }PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();// ...icontext.addPropertyDescriptors(descriptors);
}

java\beans\Introspector.java

public static BeanInfo getBeanInfo(Class<?> beanClass){// ...// 这里获取的 BeanInfo beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();// ...return beanInfo;
}private BeanInfo getBeanInfo() throws IntrospectionException {// ...// 这里获取的 PropertyDescriptor[]PropertyDescriptor pds[] = getTargetPropertyInfo();return new GenericBeanInfo(bd, esds, defaultEvent, pds,defaultProperty, mds, explicitBeanInfo);
}private PropertyDescriptor[] getTargetPropertyInfo() {// ...// 跟踪到这里发现在 PropertyInfo 中就没有获取到属性的set方法,最终锁定 ClassInfo.getProperties() 方法for (Map.Entry<String,PropertyInfo> entry : ClassInfo.get(this.beanClass).getProperties().entrySet()) {addPropertyDescriptor(null != entry.getValue().getIndexed()? new IndexedPropertyDescriptor(entry, this.propertyChangeSource): new PropertyDescriptor(entry, this.propertyChangeSource));}// ...
}

com\sun\beans\introspect\ClassInfo.java

public Map<String,PropertyInfo> getProperties() {if (this.properties == null) {synchronized (this.mutex) {if (this.properties == null) {this.properties = PropertyInfo.get(this.type);}}}return this.properties;
}

com\sun\beans\introspect\PropertyInfo.java

public static Map<String,PropertyInfo> get(Class<?> type) {List<Method> methods = ClassInfo.get(type).getMethods();if (methods.isEmpty()) {return Collections.emptyMap();}Map<String,PropertyInfo> map = new TreeMap<>();for (Method method : methods) {if (!Modifier.isStatic(method.getModifiers())) {Class<?> returnType = method.getReturnType();String name = method.getName();switch (method.getParameterCount()) {case 0:if (returnType.equals(boolean.class) && isPrefix(name, "is")) {PropertyInfo info = getInfo(map, name.substring(2), false);info.read = new MethodInfo(method, boolean.class);} else if (!returnType.equals(void.class) && isPrefix(name, "get")) {PropertyInfo info = getInfo(map, name.substring(3), false);info.readList = add(info.readList, method, method.getGenericReturnType());}break;case 1:// 最终就是在这里跳过了 set 方法,因为 returnType 不是 voidif (returnType.equals(void.class) && isPrefix(name, "set")) {PropertyInfo info = getInfo(map, name.substring(3), false);info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[0]);} else if (!returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "get")) {PropertyInfo info = getInfo(map, name.substring(3), true);info.readList = add(info.readList, method, method.getGenericReturnType());}break;case 2:if (returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "set")) {PropertyInfo info = getInfo(map, name.substring(3), true);info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[1]);}break;}}}Iterator<PropertyInfo> iterator = map.values().iterator();while (iterator.hasNext()) {if (!iterator.next().initialize()) {iterator.remove();}}return !map.isEmpty()? Collections.unmodifiableMap(map): Collections.emptyMap();
}

PropertyUtils.copyProperties 属性值复制失败相关推荐

  1. 将对象的属性值复制到另一个对象中

    将对象的属性值复制到另一个对象中 /**** 将第一个对象的属性值复制到第二个对象中* @param <T> 第一个对象* @param <R> 第二个对象*/ class H ...

  2. java对象上有横线_对象bean间属性值复制:无视大小写和下划线_和横杠-

    1.简要说明:在java代码开发过程中,总会遇到实体类bean直接的属性复制问题,将一个bean中的值复制到另一个bean中,这时如果属性名是形同的,(仅仅有大小写或带下划线_或带横杠-)的区别,那就 ...

  3. beanutils.copyproperties属性值丢失_[ASP.NET Core 3.1]浏览器嗅探解决部分浏览器丢失Cookie问...

    今天的干货长驱直入,直奔主题 看了前文的同学们应该都知道,搜狗.360等浏览器在单点登录中反复重定向,最终失败报错. 原因在于,非Chrome80+浏览器不识别Cookie上的SameSite=non ...

  4. copyproperties爆红_BeanUtils.copyProperties复制失败探究

    一 BeanUtils.copyProperties是什么 BeanUtils类全路径为org.springframework.beans.BeanUtils是spring-beans包下的一个用于b ...

  5. java 将对象属性值快速复制到另一个对象上

    需求:将对象属性值快速复制到另一个对象上,忽略空值属性和id 直接上代码:BeanUtils 工具类 注意:如果需要关注复制性能的话,推荐用插件https://blog.csdn.net/qiaoda ...

  6. 复制类中的属性值到另一个类的相同属性中

    代码有好多高级代码,现在给大家看一个,就是复制相同属性的值到另一个类. 例如:A类中有String name,int score:B类中有String name ,int score,String s ...

  7. js中复制对象的属性值给新的对象

    我们有一个对象,且包含很多属性值和方法,但是我们想把它的内部属性复制给一个新的对象时,我们如何去做呢? 你可能会说直接 a = b就可以了. no no no,这样两个对象其实指针指向的还是一个内存中 ...

  8. arcgis表转excel一直失败_Excel表转换为shp格式时属性值丢失问题

    早前在网上扒拉一些数据,放到excel中进行加工,然后加载到arcgis中,生成点要素,然后转为shp格式文件.但是在此过程中遇到了一些小问题,有些字段的信息在转换过程中会丢失.一开始我以为是我的ex ...

  9. BeanUtils.copyProperties VS PropertyUtils.copyProperties

    1. 通过反射将一个对象的值赋值个另外一个对象(前提是对象中属性的名字相同). 2. BeanUtils.copyProperties(obj1,obj2); 经常闹混不知道是谁给谁赋值,无意中先到& ...

  10. java 获取对象属性值为空或者非空的属性名称

    目录 1. 获取对象属性值为空的属性名称 2. 复制对象非空属性值 1. 获取对象属性值为空的属性名称 /** * @Title: getNullPropertyNames* @Description ...

最新文章

  1. API sklearn.neighbors.KNeighborsClassifier
  2. 如何用DiscoGAN学习发现跨域关系(附源代码)
  3. 使用容器与云计算技术快速进行深度学习
  4. CSS设置无需表格的菜单
  5. Python json使用实例:字符串与对象互转代码示例
  6. 太极创客ESP8266 - NodeMCU、JSON、MQTT教程(基于Arduino)
  7. 实地探访重庆“最复杂立交”:其实并不容易走错路
  8. php _trait,php Trait的使用
  9. 中国大推力矢量发动机WS15 跨入 世界先进水平!
  10. 《学习OpenCV3》第10章 滤波与卷积
  11. 电脑桌面点任何文件都打开计算机,小编教你电脑开机自动打开文件夹怎么解决...
  12. IOS底层数据结构--class
  13. 贵阳市建筑物矢量数据(Shp格式+带高度)
  14. UE4 蓝图文档阅读笔记
  15. C语言程序设计实验报告——实验五
  16. Jmeter之连接MySQL数据库操作
  17. Matlab 使用四阶龙格库塔求解二阶隐式微分方程_ode45
  18. Beta 反(tu)思(cao) 获小黄衫感言
  19. 解决resetFields报错 underfined
  20. Springboot毕设项目管易tms运输智能监控管理系统663kq(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. 学习笔记:人工势场法
  2. 传统人工势场法---经典算法
  3. 需求调研报告模板_培训需求调研报告不会写,遇到问题咋解决?
  4. java sts安装步骤_下载并安装Java开发工具STS
  5. ae效果英文版翻译对照表_AE中英文对照
  6. ffmpeg 反复推流_FFmpeg 推流问题记录
  7. 深度学习-模型预测(论文笔记)
  8. Log4j(三)——Log4j配置文件位置详解
  9. 微计算机与单片机原理及应用答案,单片机原理及应用(张毅刚)完整答案[一].pdf...
  10. 高层建筑电气设计说明书