根据对象层次路径动态获取和设置值

先看一段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

不仅仅是获取, 我还希望可以对这个深层次的对象进行赋值 所以有了这个小例子

先定义数据结构

  1. OrderInfoDTO
import lombok.Data;
import lombok.ToString;

import java.util.List;

@Data
@ToString
public class OrderInfoDTO {
    private GoOrderDTO goOrder;
    private List<WmsPlanDTO> wmPlans;
}
  1. 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;
}
  1. 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;
}
  1. 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;
}

定义反射方法这是我们的核心

  1. 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;
    }
}
  1. 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;
    }
}