根据对象层次路径动态获取和设置值
先看一段json
{
"wmPlans":
[
{
"skuInfos":
[
{
"customerItemNO":"no-03",
"goCargoId":"go03"
},
{
"customerItemNO":"no-04",
"goCargoId":"go04",
"extensionParameter":
{
"invNo":"abcd01",
"bu":"BM"
}
}
],
"warehouseType":"wmsHouse1",
"warehousedocumentType":"wmsDocument1"
},
{
"skuInfos":
[
{
"customerItemNO":"no-03",
"goCargoId":"go03"
},
{
"customerItemNO":"no-04",
"goCargoId":"go04"
}
],
"warehouseType":"wmsHouse2",
"warehousedocumentType":"wmsDocument2"
}
],
"goOrder":
{
"extionParam":
{
"bbb":"ccc"
},
"skuInfos":
[
{
"customerItemNO":"no-01",
"goCargoId":"go01"
},
{
"customerItemNO":"no-02",
"goCargoId":"go02"
}
],
"i3":20,
"mark3":"mark3",
"consignorCode":"ConsignorCode01"
}
}
我希望能根据一个路径
例如
goOrder.skuInfos.customerItemNO 获取到两个值 no-01 no-02
goOrder.skuInfos[0].customerItemNO 获取到 no-01
wmPlans.skuInfos.customerItemNO 获取到 no-03 no-04 no-03 no-04
wmPlans[0].skuInfos.customerItemNO 获取到 no-03 no-04
wmPlans.skuInfos[0].customerItemNO 获取到 no-03 no-03
不仅仅是获取, 我还希望可以对这个深层次的对象进行赋值 所以有了这个小例子
先定义数据结构
- OrderInfoDTO
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class OrderInfoDTO {
private GoOrderDTO goOrder;
private List<WmsPlanDTO> wmPlans;
}
- GoOrderDTO
import lombok.Data;
import lombok.ToString;
import java.util.List;
import java.util.Map;
@Data
@ToString
public class GoOrderDTO {
private String consignorCode;
private String mark3;
private Integer i3;
private List<SkuInfoDTO> skuInfos;
private Map<String, String> extionParam;
}
- WmsPlanDTO
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class WmsPlanDTO {
private String warehouseType;
private String warehousedocumentType;
private List<SkuInfoDTO> skuInfos;
}
- SkuInfoDTO
import lombok.Data;
import lombok.ToString;
import java.util.Map;
@Data
@ToString
public class SkuInfoDTO {
private String customerItemNO;
private String goCargoId;
private Map<String, String> extensionParameter;
}
定义反射方法这是我们的核心
- ReflectGetPathValRes
import lombok.Data;
@Data
public class ReflectGetPathValRes {
private Boolean success;
private String val;
public ReflectGetPathValRes(Boolean success, String val) {
this.success = success;
this.val = val;
}
}
- ReflectUtil 这个类方法里面很多重复代码,可以考虑封装成函数
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Field;
import java.util.*;
public class ReflectUtil {
/**
* 通过反射,对rootObj 对象 对应conditionPath路径 赋值为val
* @param rootObj
* @param conditionPath
* @param val
* @return
*/
public static boolean reflectAssignEvaluate(Object rootObj, String conditionPath, Object val) {
if (conditionPath.isEmpty()) {
System.out.println("条件比较路径发生空值错误错误");
return false;
}
String[] paths = StringUtils.split(conditionPath, '.');
int pathsLen = paths.length;
Object currObj = rootObj;
Object[] objArr = new Object[pathsLen+1];
objArr[0] = rootObj;
for(int i=0; i <= pathsLen-1; i++) {
try{
Class currObjClass = currObj.getClass();
String currGetDeclaredPath = paths[i];
// 虽然命名是mapKey 但是他也会获取到list的索引值
String mapKey = "";
if (StringUtils.contains(currGetDeclaredPath, '[')) {
currGetDeclaredPath = paths[i].substring(0, paths[i].indexOf('['));
mapKey = paths[i].substring(paths[i].indexOf('[')+1, paths[i].indexOf(']'));
}
Field currObjField = currObjClass.getDeclaredField(currGetDeclaredPath);
currObjField.setAccessible(true);
currObj = currObjField.get(currObj);
if(currObj != null) {
objArr[i+1] = currObj;
}
//如果获取到当前对象为空,并且路径不是最后一级,则为错误
if (currObj == null && i < pathsLen-1) {
System.out.println(currObjField.getType().getTypeName()+"."+currObjField.getName()+"为空,下一级属性无法获取及赋值");
return false;
}
//赋值操作
if(i == pathsLen-1) {
return objAssignEvaluate(currObjField, objArr[i], val, mapKey);
}
if (currObjField.getType().getTypeName().contains("List")) {
List srcList=(List)currObj;
String newPaths = StringUtils.join(arraySub(paths, i+1, pathsLen),'.');
if (StringUtils.isNotBlank(mapKey) && StringUtils.isNumeric(mapKey)) {
int mapKeyIndex = Integer.parseInt(mapKey);
srcList.get(mapKeyIndex);
return reflectAssignEvaluate(srcList.get(mapKeyIndex), newPaths, val);
} else {
boolean assignEvaluateRes = true;
for(Object src : srcList) {
if (!reflectAssignEvaluate(src, newPaths, val)) {
assignEvaluateRes = false;
}
}
return assignEvaluateRes;
}
}
}catch (NoSuchFieldException | IllegalAccessException e) {
System.out.println(e.getMessage());
return false;
}
}
return true;
}
/**
* 利用反射,校验条件路径下对象中的值是否与期望值相同
* 期望值都是String类型,因为是从数据库中获取到的,所以无法判定具体类型
* @param rootObj
* @param conditionPath
* @param expVal
* @return
*/
public static boolean reflectCheckCondition(Object rootObj, String conditionPath, String expVal) {
ReflectGetPathValRes getValRes = reflectGetPathVal(rootObj, conditionPath);
if (getValRes.getSuccess()) {
if (Objects.isNull(getValRes.getVal())) {
getValRes.setVal("");
}
return StringUtils.equals(getValRes.getVal(), expVal);
}
return false;
}
/**
* 通过反射,对rootObj 对象 对应conditionPath路径 代表得值
* 本方法支持map对应得key值
* list获取对应索引后得内容
* @param rootObj
* @param conditionPath
* @return
*/
public static ReflectGetPathValRes reflectGetPathVal(Object rootObj, String conditionPath) {
if (conditionPath.isEmpty()) {
System.out.println("条件比较路径发生空值错误错误");
return new ReflectGetPathValRes(false,"");
}
String[] paths = StringUtils.split(conditionPath, '.');
int pathsLen = paths.length;
Object currObj = rootObj;
Object[] objArr = new Object[pathsLen+1];
objArr[0] = rootObj;
for(int i=0; i <= pathsLen-1; i++) {
try{
Class currObjClass = currObj.getClass();
String currGetDeclaredPath = paths[i];
String mapKey = "";
if (StringUtils.contains(currGetDeclaredPath, '[')) {
currGetDeclaredPath = paths[i].substring(0, paths[i].indexOf('['));
mapKey = paths[i].substring(paths[i].indexOf('[')+1, paths[i].indexOf(']'));
}
Field currObjField = currObjClass.getDeclaredField(currGetDeclaredPath);
currObjField.setAccessible(true);
currObj = currObjField.get(currObj);
if(currObj != null) {
objArr[i+1] = currObj;
}
//如果获取到当前对象为空,并且路径不是最后一级,则为错误
if (currObj == null && i < pathsLen-1) {
System.out.println(currObjField.getType().getTypeName()+"."+currObjField.getName()+"为空,下一级属性无法获取及赋值");
return new ReflectGetPathValRes(false,"");
}
//赋值操作
if(i == pathsLen-1) {
return new ReflectGetPathValRes(true,fromObjGetFieldValue(currObjField, objArr[i], mapKey));
}
if (currObjField.getType().getTypeName().contains("List")) {
List srcList=(List)currObj;
String newPaths = StringUtils.join(arraySub(paths, i+1, pathsLen),'.');
if (StringUtils.isNotBlank(mapKey)) {
return reflectGetPathVal(srcList.get(Integer.parseInt(mapKey)),newPaths);
}
List<Object> resList = new ArrayList<>();
for(Object src : srcList) {
// return reflectGetPathVal(src,newPaths);
ReflectGetPathValRes getPathValRes = reflectGetPathVal(src,newPaths);
// 检查 getPathValRes.getVal() 是否是一个jsonarray
if (getPathValRes.getVal().startsWith("[")) {
resList.addAll(JSONUtil.toList(JSONUtil.parseArray(getPathValRes.getVal()), Object.class));
} else {
resList.add(getPathValRes.getVal());
}
}
return new ReflectGetPathValRes(true, JSONUtil.toJsonStr(resList));
}
}catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
return new ReflectGetPathValRes(false,"");
}
}
return new ReflectGetPathValRes(false,"");
}
public static boolean objAssignEvaluate(Field field, Object rootObj, Object val, String mapKey) throws IllegalAccessException {
if (field.getType().getName().contains("Integer")) {
field.set(rootObj, Integer.parseInt(String.valueOf(val)));return true;
}else if (field.getType().getName().contains("String")) {
field.set(rootObj, String.valueOf(val));
} else if (field.getType().getName().contains("Map")) {
Map<String, String> currMap = (Map<String, String>) field.get(rootObj);
if (currMap == null) {
currMap = new HashMap<>();
}
currMap.put(mapKey, String.valueOf(val));
field.set(rootObj, currMap);
} else if (field.getType().getName().contains("List")) {
List srcList=(List)field.get(rootObj);
if (srcList == null) {
srcList = new ArrayList();
}
if (StringUtils.isNotBlank(mapKey) && StringUtils.isNumeric(mapKey)) {
int index = Integer.valueOf(mapKey);
srcList.set(index, val);
// field.set(rootObj, srcList);
} else {
field.set(rootObj, val);
}
}
//其他类型的强制转换
return true;
}
/**
* 从rootObj中获取字段field得值
* @param field
* @param rootObj
* @param mapKey
* @return
* @throws IllegalAccessException
*/
public static String fromObjGetFieldValue(Field field, Object rootObj, String mapKey) throws IllegalAccessException {
if (field.getType().getName().contains("Integer")) {
Integer realVal = (Integer)field.get(rootObj);
return String.valueOf(realVal);
} else if (field.getType().getName().contains("String")) {
return (String)field.get(rootObj);
} else if (field.getType().getName().contains("Map")) {
Map<String, String> currMap = (Map<String, String>) field.get(rootObj);
return currMap.get(mapKey);
} else if (field.getType().getName().contains("List")) {
List srcList=(List)field.get(rootObj);
// mapkey不是空并且他还是一个数字
if (StringUtils.isNotBlank(mapKey) && StringUtils.isNumeric(mapKey)) {
int index = Integer.valueOf(mapKey);
return JSONUtil.toJsonStr(srcList.get(index));
}
return JSONUtil.toJsonStr(srcList);
}
//其他类型的强制转换
return "";
}
public static String[] arraySub(String[] data, int start, int end) {
String[] c = new String[end-start];
int j = 0;
for(int i=start; i<end; i++){
c[j] = data[i];
j++;
}
return c;
}
//对对象中所有字符串类型的空对象赋值空字符串
public static void javaBeanNullStrToEmptyStr(Object obj){
Class currObjClass = obj.getClass();
Field[] fields = currObjClass.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
if (field.getType().getName().contains("String")) {
try {
String currValue = (String) field.get(obj);
if (StringUtils.isBlank(currValue)) {
objAssignEvaluate(field, obj, "", "");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println(e.toString());
}
}
}
}
}
接下来我们进行测试
TestMain.java
import cn.hutool.json.JSONUtil;
import java.util.*;
public class TestMain {
public static void main(String[] args) {
OrderInfoDTO orderInfoDTO = initData();
System.out.println(JSONUtil.formatJsonStr(JSONUtil.toJsonStr(orderInfoDTO)));
/********************************************************************************/
// 第一次测试 一个正常的属性路径
// String path1 = "goOrder.consignorCode";
// String expValTrue="ConsignorCode01";
// // 检查一个正确的值
// boolean res11 = ReflectUtil.reflectCheckCondition(orderInfoDTO, path1, expValTrue);//true
// System.out.println(res11); // true
//
// // 重新赋值
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path1, "ConsignorCode03");
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path1)); // ConsignorCode03
/********************************************************************************/
// 第二次测试 一个arraylist的属性路径
// String path2 = "goOrder.skuInfos";
// String expValTrue="[{\"customerItemNO\":\"no-01\",\"goCargoId\":\"go01\"},{\"customerItemNO\":\"no-02\",\"goCargoId\":\"go02\"}]";
// boolean resTrue = ReflectUtil.reflectCheckCondition(orderInfoDTO, path2, expValTrue);
// System.out.println(resTrue);
// List<SkuInfoDTO> skuList = new ArrayList<>();
// SkuInfoDTO skuInfoDTO1 = new SkuInfoDTO();
// skuInfoDTO1.setGoCargoId("goSku01");
// skuInfoDTO1.setCustomerItemNO("noSKU01");
//
// SkuInfoDTO skuInfoDTO2 = new SkuInfoDTO();
// skuInfoDTO2.setGoCargoId("goSku02");
// skuInfoDTO2.setCustomerItemNO("noSku02");
// skuList.add(skuInfoDTO1);
// skuList.add(skuInfoDTO2);
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path2, skuList);
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path2));
/********************************************************************************/
// 第三次测试对数组中的某个元素的属性路径
// String path3 = "goOrder.skuInfos[0].goCargoId";
// String expValTrue="go01";
//
// boolean resTrue = ReflectUtil.reflectCheckCondition(orderInfoDTO, path3, expValTrue);
// System.out.println(resTrue); // true
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path3, "goCargo01");
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO)); // goCargo01
/********************************************************************************/
// 第四次测试 数组的指定索引进行赋值和取值
// String path4 = "goOrder.skuInfos[0]";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path4));
// String expValTrue="{\"customerItemNO\":\"no-01\",\"goCargoId\":\"go01\"}";
// boolean resTrue = ReflectUtil.reflectCheckCondition(orderInfoDTO, path4, expValTrue);
//
// SkuInfoDTO skuInfoDTO1 = new SkuInfoDTO();
// skuInfoDTO1.setGoCargoId("goSku01");
// skuInfoDTO1.setCustomerItemNO("noSKU01");
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path4, skuInfoDTO1);
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path4));
/********************************************************************************/
// 第五次测试 此次测试的赋值无意义,几乎不会有吧所有数组元素赋值成完全一样内容的需求
// String path5 = "wmPlans.skuInfos";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path5));
// 这样取值会将上层数组平铺开然后展示出来 [{"customerItemNO":"no-01","goCargoId":"go01"},{"customerItemNO":"no-02","goCargoId":"go02"},{"customerItemNO":"no-03","goCargoId":"go03"},{"customerItemNO":"no-04","goCargoId":"go04","extensionParameter":{"bbb":"ccc"}}]
/********************************************************************************/
// 第六次测试 第一层是数组,第二层指定索引
// String path6 = "wmPlans.skuInfos[0].customerItemNO";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path6));
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path6, "shishi");
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
// 第七次测试 第一层是数组指定索引,第二层是数组
// String path7 = "wmPlans[0].skuInfos.customerItemNO";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path7));
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path7, "shishi");
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path7));
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
// 第八次测试 第一层是数组,然后跟一个普通的属性
// String path8 = "wmPlans.warehouseType";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path8));
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO, path8, "warehouseTypeTh8");
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path8));
/********************************************************************************/
// String path9 = "goOrder.skuInfos.goCargoId";
// System.out.println(ReflectUtil.reflectGetPathVal(orderInfoDTO, path9));
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO,path9, "123456");
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
// 第十次测试 给 所有的wmPlans 里面所有的sku 添加扩展属性 aaa = wmsplanPath10keyaaaValue
// String path10 = "wmPlans.skuInfos.extensionParameter[aaa]";
// String val3="wmsplanPath10keyaaaValue";
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO,path10, val3);
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
// 第十一次测试给 wmPlans[0] 的 所有sku 添加扩展属性 aaa = wmsplanPath10keyaaaValue
// String path11 = "wmPlans[0].skuInfos.extensionParameter[aaa]";
// String val11="wmsplanPath11keyaaaValue";
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO,path11, val11);
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
// 第十一次测试 给 所有的wmPlans 的 skuInfos[1] 添加扩展属性 aaa = wmsplanPath12keyaaaValue
// String path12 = "wmPlans.skuInfos[1].extensionParameter[aaa]";
// String val12="wmsplanPath12keyaaaValue";
// ReflectUtil.reflectAssignEvaluate(orderInfoDTO,path12, val12);
// System.out.println(JSONUtil.toJsonStr(orderInfoDTO));
/********************************************************************************/
}
public static OrderInfoDTO initData() {
SkuInfoDTO skuInfoDTO1 = new SkuInfoDTO();
skuInfoDTO1.setGoCargoId("go01");
skuInfoDTO1.setCustomerItemNO("no-01");
SkuInfoDTO skuInfoDTO2 = new SkuInfoDTO();
skuInfoDTO2.setGoCargoId("go02");
skuInfoDTO2.setCustomerItemNO("no-02");
Map<String, String> goOrderEXTMap1 = new HashMap<>();
goOrderEXTMap1.put("bbb", "ccc");
List<SkuInfoDTO> goOrderSKUInfos = new ArrayList<>();
goOrderSKUInfos.add(skuInfoDTO1);
goOrderSKUInfos.add(skuInfoDTO2);
GoOrderDTO goOrderDTO = new GoOrderDTO();
goOrderDTO.setConsignorCode("ConsignorCode01");
goOrderDTO.setMark3("mark3");
goOrderDTO.setI3(20);
goOrderDTO.setSkuInfos(goOrderSKUInfos);
goOrderDTO.setExtionParam(goOrderEXTMap1);
// goOrder赋值完成
SkuInfoDTO wmsSku0101 = new SkuInfoDTO();
wmsSku0101.setGoCargoId("go03");
wmsSku0101.setCustomerItemNO("no-03");
SkuInfoDTO wmsSku0102 = new SkuInfoDTO();
wmsSku0102.setGoCargoId("go04");
wmsSku0102.setCustomerItemNO("no-04");
Map<String, String> wmsSku0102ExtionParam = new HashMap<>();
wmsSku0102ExtionParam.put("invNo", "abcd01");
wmsSku0102ExtionParam.put("bu", "BM");
wmsSku0102.setExtensionParameter(wmsSku0102ExtionParam);
WmsPlanDTO wmsPlanDTO1 = new WmsPlanDTO();
wmsPlanDTO1.setWarehouseType("wmsHouse1");
wmsPlanDTO1.setWarehousedocumentType("wmsDocument1");
wmsPlanDTO1.setSkuInfos(Arrays.asList(wmsSku0101, wmsSku0102));
// wmsPlanDTO1赋值完成
SkuInfoDTO wmsSku0201 = new SkuInfoDTO();
wmsSku0201.setGoCargoId("go03");
wmsSku0201.setCustomerItemNO("no-03");
SkuInfoDTO wmsSku0202 = new SkuInfoDTO();
wmsSku0202.setGoCargoId("go04");
wmsSku0202.setCustomerItemNO("no-04");
Map<String, String> wmsSku0202ExtionParam = new HashMap<>();
wmsSku0202ExtionParam.put("invNo", "abcd01");
wmsSku0202ExtionParam.put("bu", "BM");
wmsSku0102.setExtensionParameter(wmsSku0202ExtionParam);
WmsPlanDTO wmsPlanDTO2 = new WmsPlanDTO();
wmsPlanDTO2.setWarehouseType("wmsHouse2");
wmsPlanDTO2.setWarehousedocumentType("wmsDocument2");
wmsPlanDTO2.setSkuInfos(Arrays.asList(wmsSku0201, wmsSku0202));
// wmsPlanDTO2赋值完成
OrderInfoDTO orderInfoDTO = new OrderInfoDTO();
orderInfoDTO.setGoOrder(goOrderDTO);
orderInfoDTO.setWmPlans(Arrays.asList(wmsPlanDTO1, wmsPlanDTO2));
return orderInfoDTO;
}
}