BeanUtils.copyProperties,拷贝后,修改target对象的字段,如果保证source对象字段不会变化
问题
我今天碰到一个高德省市区转换的问题,高德省市区数据拉过来的时候,澳门和香港2级下没有3级节点,我想在澳门和香港2级节点下增加一个3级节点,通过BeanUtils.copyProperties后(这里说一句,Spring的BeanUtils在高并发下慢,参考我之前的文章)然后我去修改target对象中treeLevel字段=3和level=city,因为我是从2级节点下copy过来的,我修改之后2级节点的treeLevel和level同样发生了变化,根本原因在于这次拷贝是浅拷贝,source和target中对象引用指向的是同一个对象地址值。
拷贝对象结果
source和target对象结构
@Data
public class GaoDeAreaTreeVO {
/**
* 当前节点
*/
private GaoDeAreaVO gaoDeArea;
/**
* 下级节点
*/
private List<GaoDeAreaTreeVO> children;
}
GaoDeArea
@Data
public class GaoDeAreaVO {
/**
* ID
*/
@ApiModelProperty("ID")
private Long id;
/**
* 节点名称
*/
@ApiModelProperty("节点名称")
private String name;
/**
* 父级
*/
@ApiModelProperty(value = "父级")
private Long parentId;
/**
* 全名称 , 号分隔
*/
@ApiModelProperty(value = "全名称 , 号分隔")
private String fullName;
/**
* 全id , 号分隔
*/
@ApiModelProperty(value = "全id , 号分隔")
private String treePath;
/**
* 树形结构等级
*/
@ApiModelProperty(value = "树形结构等级")
private Integer treeLevel;
/**
* 地区等级
*/
@ApiModelProperty(value = "地区等级")
private String level;
/**
* 中心点经度
*/
@ApiModelProperty(value = "中心点经度")
private BigDecimal centerLng;
/**
* 中心点纬度
*/
@ApiModelProperty(value = "中心点纬度")
private BigDecimal centerLat;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
* 首字母
*/
@ApiModelProperty(value = "首字母")
private String initials;
}
老代码
当这行代码执行了city.setTreeLevel(3),gaoDeArea这个对象中的treeLevel也发生了变化,原因在于gaoDeArea这个对象拷贝之后,指向的是同一个内存地址值。
// 香港澳门特殊处理 补全city一级(用省一级的信息补全节点)
GaoDeAreaTreeVO areaTreeVO = categoryTreeVOList.get(0);
List<GaoDeAreaTreeVO> childCategoryList = areaTreeVO.getChildren();
for (GaoDeAreaTreeVO tree : childCategoryList) {
GaoDeAreaVO gaoDeArea = tree.getGaoDeArea();
if (HK_CODE.equals(gaoDeArea.getId()) || MC_CODE.equals(gaoDeArea.getId())) {
GaoDeAreaTreeVO temp = new GaoDeAreaTreeVO();
BeanUtils.copyProperties(tree, temp);
GaoDeAreaVO city = temp.getGaoDeArea();
city.setTreeLevel(3);
city.setLevel("city");
tree.setChildren(Collections.singletonList(temp));
}
解决办法
第一种办法
手动set,我的字段太多了,我不想set,这种办法我直接不考虑,丢。
第二种办法
我在拷贝GaoDeAreaTreeVO 这个对象的时候,gaoDeArea这个字段我忽略掉,不拷贝,然后我单独拷贝这个gaoDeArea,然后在设置到GaoDeAreaTreeVO对象的gaoDeArea字段上,完美解决。
// 香港澳门特殊处理 补全city一级(用省一级的信息补全节点)
GaoDeAreaTreeVO areaTreeVO = categoryTreeVOList.get(0);
List<GaoDeAreaTreeVO> childCategoryList = areaTreeVO.getChildren();
for (GaoDeAreaTreeVO tree : childCategoryList) {
GaoDeAreaVO gaoDeArea = tree.getGaoDeArea();
if (HK_CODE.equals(gaoDeArea.getId()) || MC_CODE.equals(gaoDeArea.getId())) {
GaoDeAreaTreeVO temp = new GaoDeAreaTreeVO();
// 忽略掉gaoDeArea
BeanUtil.copyProperties(tree, temp, "gaoDeArea");
// 单独拷贝
GaoDeAreaVO city = new GaoDeAreaVO();
BeanUtil.copyProperties(gaoDeArea, city);
city.setTreeLevel(3);
city.setLevel("city");
// 再设置到GaoDeAreaTreeVO 这个对象当中
temp.setGaoDeArea(city);
tree.setChildren(Collections.singletonList(temp));
}
}