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, var4, 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-08-02 19:04:42 +08:00
因为 List 里的泛型擦除了
|
3
sLvxq6Ya 2022-08-02 19:12:42 +08:00 1
对 BeanUtils 不是很熟悉,推测你这个问题应该是因为 Java 的泛型擦除
Java 的泛型只在编译期进行类型检查,而 BeanUtils 的 Set 是通过运行时反射,不需要经过类型检查 所以执行的时候就相当于给 courseCategoryResponse 的 List<Object> children(原本声明要求 List<CourseCategoryResponse>) 赋值了一个 List<Object> (实际上是 List<Category>), set 时都是 List<Object>不会报错,但是 get 时你可能通过指定变量类型做了一个类型转换,就会报错。 |
4
xaplux 2022-08-03 08:38:29 +08:00
2 楼正解
|
5
lifespy 2022-08-03 14:30:52 +08:00
|
6
Saxton 2022-08-03 22:46:17 +08:00 via iPhone
2 楼正解,这就是反射带来的影响
|
7
Saxton 2022-08-03 22:48:50 +08:00 via iPhone 1
另外我不推荐用 beanUtils 来实现对象的拷贝,本身反射是一种非常危险的行为,并不能在编译的时候发现问题,推荐楼主使用 mapStruct ,编译时会自动生成一个 set 方法
|