spring BeanUtils.copyProperties 版本更新赋值失败

发布时间 2023-10-08 22:34:11作者: 冷扑星

今天遇到了个小问题 是由于springboot 版本升级导致的 BeanUtils.copyProperties 赋值失败,结果就导致了用户无法登录的问题

目前的版本是

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.9</version> <!-- lookup parent from repository -->
</parent>

之前的版本是

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version> <!-- lookup parent from repository -->
</parent>

在之前的版本(2.2.6)的时候在赋值2个属性的时候他的比较是否可以赋值的方法是

if (readMethod != null &&
      ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
 }

在版本2.6.9的时候 比较是否可以进行复制的方法又变成了

boolean isAssignable =
      (sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
            ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
            targetResolvableType.isAssignableFrom(sourceResolvableType));

在debug 的时候发现前面的2个都是false

这个是方法hasUnresolvableGenerics 翻译过来就是查看有没有泛型 正好那个属性是list 并且设置了泛型 于是就2个都是false 进入了isAssignableFrom(sourceResolvableType)

Determine whether the underlying type has any unresolvable generics: either through an unresolvable type variable on the type itself or through implementing a generic interface in a raw fashion, i.e. without substituting that interface's type variables. The result will be true only in those two scenarios.

isAssignableFrom的注释 翻译过来就是会根据class的类型来进行判断是否可以赋值 而这个之前也提到了是不同的类型 于是就导致了赋值失败

Determine whether this ResolvableType is assignable from the specified other type.
Attempts to follow the same rules as the Java compiler, considering whether both the resolved Class is assignable from the given type as well as whether all generics are assignable.
Params:
other – the type to be checked against (as a ResolvableType)
Returns:
true if the specified other type can be assigned to this ResolvableType; false otherwise

具体比较方法

if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) {
   return false;
}

总结:

其实这里面是真的是命名的问题,就是List 里面 在进行BeanUtils.copyProperties 的时候,2个bean 的Role 对象根本就不是同一个,只不是就是名字是一样的,就导致了没有第一时间发现这个问题,并且因为当时想的是好好的代码怎么改了版本就不行了,所以当时聚焦的问题其实是在版本不同的方法改动上

一开始我确实都用的是BeanUtils.copyProperties ,这样的api很方便,然后接触到了mapstruct之后用了这个 ,再往后,又有人和我说,这些的bean属性的赋值上最好还是通过原先的set方法来进行赋值,这样可以直观的看到属性的传递