
public class CourseCategoryResponse { private String id; @ApiModelProperty("分类名称") private String name; @ApiModelProperty("分类图标") private String image; @ApiModelProperty("英文名称") private String nameEn; @ApiModelProperty("子分类") private List<CourseCategoryResponse> children; @ApiModelProperty("课程列表") private List<CourseSimpleResponse> coures; } public class Category { @Id @Column(length = 37) @GeneratedValue(generator = "jpa-uuid") private String id; @ApiParam("主体") @Column(length = 32) private String subject; @ApiParam("分类名称") @Column(length = 32) private String name; private List<Category> children; } ==========调用代码===================== PropertyDescriptor propertyDescriptors = BeanUtils.getPropertyDescriptor(CourseCategoryResponse.class,"children"); CourseCategoryResponse courseCategoryRespOnse= new CourseCategoryResponse(); Category category = new Category(); category.setName("123"); Category children = new Category(); children.setName("234"); category.setChildren(List.of(children)); PropertyDescriptor source = BeanUtils.getPropertyDescriptor(Category.class,"children"); Object value = source.getReadMethod().invoke(category); propertyDescriptors.getWriteMethod().invoke(courseCategoryResponse,value); System.out.println(courseCategoryResponse); 打印结果 courseCategoryResponse 的 children 是有值的,我想这个为什么可以 set 进去 经过一段源码阅读,很好奇fastjson是怎样序列化,它是怎样判断children类型,先通过反射类的方法和属性,然后生成一堆拼接json的代码,为什么要这样,生成一个类就可以重用,不用每次都反射,效率太慢,mapStuct也是这样原理 其中这段代码
List var13 = (List)var10.getChildren(); public class ASMSerializer_1_CourseCategoryResponse extends JavaBeanSerializer implements ObjectSerializer { public Type children_asm_fieldType = ASMUtils.getMethodType(CourseCategoryResponse.class, "getChildren"); public ObjectSerializer children_asm_list_item_ser_; public ObjectSerializer children_asm_ser_; public Type coures_asm_fieldType = ASMUtils.getMethodType(CourseCategoryResponse.class, "getCoures"); public ObjectSerializer coures_asm_list_item_ser_; public ObjectSerializer coures_asm_ser_; public ASMSerializer_1_CourseCategoryResponse(SerializeBeanInfo var1) { super(var1); } public void write(JSONSerializer var1, Object var2, Object var3, Type var4, int var5) throws IOException { if (var2 == null) { var1.writeNull(); } else { SerializeWriter var9 = var1.out; if (!this.writeDirect(var1)) { this.writeNormal(var1, var2, var3, var4, var5); } else if (var9.isEnabled(32768)) { this.writeDirectNonContext(var1, var2, var3, var4, var5); } else { CourseCategoryResponse var10 = (CourseCategoryResponse)var2; if (!this.writeReference(var1, var2, var5)) { if (var9.isEnabled(2097152)) { this.writeAsArray(var1, var2, var3, va4, var5); } else { SerialContext var11 = var1.getContext(); var1.setContext(var11, var2, var3, 0); char var12 = '{'; String var6 = "children"; List var13 = (List)var10.getChildren(); 这个还有补充一点,beanUtis.copyPropertites里面是有判断类型是否能够赋值的
for (PropertyDescriptor targetPd : targetPds) { Method writeMethod = targetPd.getWriteMethod(); if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) { Method readMethod = sourcePd.getReadMethod(); if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { } } } } public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) { Assert.notNull(lhsType, "Left-hand side type must not be null"); Assert.notNull(rhsType, "Right-hand side type must not be null"); if (lhsType.isAssignableFrom(rhsType)) { return true; } else { Class resolvedPrimitive; if (lhsType.isPrimitive()) { resolvedPrimitive = (Class)primitiveWrapperTypeMap.get(rhsType); if (lhsType == resolvedPrimitive) { return true; } } else { resolvedPrimitive = (Class)primitiveTypeToWrapperMap.get(rhsType); if (resolvedPrimitive != null && lhsType.isAssignableFrom(resolvedPrimitive)) { return true; } } return false; } } 关键是上面的 isAssignable 方法,当List<Category> 赋给 List<CategoryResponse>,他们比较的是List类型,绝对不会比较List里面的类型,实在也是坑之一,所以就会能够产生上述结果
1 simonlu9 OP set 是可以 set 成功的,但是 get 会报错,json 序列化也是可以看到有值,是个坑 |
2 quericy 2022 年 8 月 2 日 因为 List 里的泛型擦除了 |
3 sLvxq6Ya 2022 年 8 月 2 日 对 BeanUtils 不是很熟悉,推测你这个问题应该是因为 Java 的泛型擦除 Java 的泛型只在编译期进行类型检查,而 BeanUtils 的 Set 是通过运行时反射,不需要经过类型检查 所以执行的时候就相当于给 courseCategoryResponse 的 List<Object> children(原本声明要求 List<CourseCategoryResponse>) 赋值了一个 List<Object> (实际上是 List<Category>), set 时都是 List<Object>不会报错,但是 get 时你可能通过指定变量类型做了一个类型转换,就会报错。 |
4 xaplux 2022 年 8 月 3 日 2 楼正解 |
5 lifespy &bsp; 2022 年 8 月 3 日 |
6 Saxton 2022 年 8 月 3 日 via iPhone 2 楼正解,这就是反射带来的影响 |
7 Saxton 2022 年 8 月 3 日 via iPhone 另外我不推荐用 beanUtils 来实现对象的拷贝,本身反射是一种非常危险的行为,并不能在编译的时候发现问题,推荐楼主使用 mapStruct ,编译时会自动生成一个 set 方法 |