背景在最近的一个项目中,我们正在和第三方联合调试一个接口。我们向对方发送http请求,然后收到对方的响应。代码很旧。代码。根据评论,对方SDK中写的Request类存在无法序列化的bug,所以这里重写了一个Request类。基本属性是一样的,关键是一个属性是静态内部类,而两个是列表属性,类似如下:AddRequest是自己重写的请求类。他们SDK中的请求类是MixAddRequest。我们组装好请求参数后,使用Spring的BeanUtils的copyProperties方法将AddRequest中的属性复制到MixAddRequest中,然后发送请求。到目前为止,可以说一切都很完美。请求失败。纳尼?对旧代码充满信心,认为一定有问题,或者他们偷偷搬了代码,把字段从optional改成了mandatory,嘿嘿。果然,他们找到了代码中的设置,现在应该确信他们的问题了,然后开始调试,准备判他们死刑。原来发给他们的请求没有这个字段。..中间只有一个Spring的copy属性的方法,当时觉得很奇怪。既然中间只有这么一行代码,那其中的玄机就一定在里面。初步怀疑是两个静态内部类不一样,于是自己写了个Demo,准备用这个BeanUtils的copyProperties方法。我写了两个类和一个Main,@Data和@ToString是lombok插件的注解,用来自动生成getter和setter方法以及toString方法。这是第一个陷阱。一开始想省事,把属性写成public。想过把getter和setter方法省掉,没有加上@Data注解。结果运行test2后,test2的所有属性都为null,一个都没有复制过来。添加@Data,继续运行。果然基本属性(String)已经复制了,但是test2里面的内部类还是null。然后验证确实是内部类的问题,简直不敢相信自己的眼睛,毕竟代码已经在线运行了这么久。..知道了问题,总是想着怎么解决,所以需要单独设置内部类,单独复制。如果内部类的bean属性比较多或者递归的bean属性比较多,可以自己封装一个方法进行递归复制。我这里只有一层,所以再复制一次。记住内部类的属性也必须有setter方法,否则会导致复制失败。你还记得我一开始提到过有两个List属性。我为什么提到这个?猜测。其实列表中的两个类也是重写的内部类,也是有区别的。那时,他们被成功复制了。为什么?因为java泛型只在编译时起作用。在运行时,列表属性是存储对象的集合。复制后,MixAddRequest的orders属性其实是Order类的集合,但不是自己内部类的集合。是AddRequest的内部类Order的集合,但是因为对方解析的是json,所以没有出现错误。..总结1.Spring的BeanUtils的CopyProperties方法需要对应属性的getter和setter方法;2、如果存在属性完全相同的内部类,但不是同一个内部类,即属于自己的内部类,spring会认为属性不同,不复制;3.泛型只在编译时起作用,不能依赖泛型来限制运行时;4、最后,spring和apache的copy属性的methodsource和destination参数的位置刚好相反,所以在导入包和调用的时候要注意。
