对象属性值按长度拆分扩展一个新集合

package com.xx.xx.core.utils;

import cn.hutool.core.util.ReflectUtil;
import com.xx.tools.utils.BeanUtil;
import com.xx.tools.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import tk.mybatis.mapper.weekend.reflection.ReflectionOperationException;

import java.beans.Introspector;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 使用方式:
 * 第一步:指定规则:拆分字段名,拆分长度
 *  List<ListSplitHelper.FieldSplitRule> fields = ListUtil.of(
 *                 ListSplitHelper.of(NursingRecordMaternal::getHandlingContent, 6)
 *         );
 * 第二步:扩展集合
 *  List<NursingRecordMaternal> dataList = ListSplitHelper.process(list,  fields, false);
 *
 *  业务场景:参考 护理文书>护理记录单>产前记录:处置或附注, 要求超出部分放到下一个单元格展示
 *
 **/
public class ListSplitHelper {

    private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");

    /**
     *
     * @Description: 扩展原集合 : 根据字段允许的最大属性值进行拆分扩展
     * @param: list 原集合
     * @param: ruleFields 待拆分的属性
     * @param isAllCopy 是否全量拷贝 : true 全量拷贝,false 只拷贝id及规则属性
     * @Return: java.util.List<T>
     * @Throws:
     * @Date: 2024/4/28 17:51
     **/
    public static <T> List<T> process(List<T> list, List<FieldSplitRule> ruleFields, boolean isAllCopy) {
        List<T> expandedList = new ArrayList<>();

        for (T original : list) {
            //包装适配
            List<FieldWrapper> fieldWrapperList = wrapper(ruleFields, original);

            //新集合长度
            Integer size = fieldWrapperList.stream().map(field -> field.getArr().length).max(Integer::compare).orElse(0);

            AtomicInteger index = new AtomicInteger(0);

            //扩展新集合
            for (int i = 0; i < size; i++) {
                T newObj = (T) ReflectUtil.newInstance(original.getClass());

                if(isAllCopy) {
                    BeanUtil.copyProperties(original, newObj);
                } else {
                    if(index.get() == 0) {
                        BeanUtil.copyProperties(original, newObj);
                    } else {
                        ReflectUtil.setFieldValue(newObj, "id", ReflectUtil.getFieldValue(original, "id"));
                    }
                }

                for (FieldWrapper wrapper : fieldWrapperList) {
                    String[] arr = wrapper.getArr();
                    if(arr.length > i) {
                        ReflectUtil.setFieldValue(newObj, wrapper.getFieldName(), arr[i]);
                    }
                }

                expandedList.add(newObj);
                index.incrementAndGet();
            }
        }

        return expandedList;
    }

    public static <T, B> FieldSplitRule of(MyFn<T, B> fieldFunction, int ruleCutLength) {
        String fieldName = fnToFieldName(fieldFunction);
        return new FieldSplitRule(fieldName, ruleCutLength);
    }

    private static <T> List<FieldWrapper> wrapper(List<FieldSplitRule> ruleFields, T object) {
        List<FieldWrapper> fieldWrapperList = ruleFields.stream()
                .map(rule -> new FieldWrapper(rule, object))
                .collect(Collectors.toList());
        return fieldWrapperList;
    }

    private static String fnToFieldName(MyFn<?, ?> fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            SerializedLambda serializedLambda = (SerializedLambda)method.invoke(fn);
            String getter = serializedLambda.getImplMethodName();
            if (GET_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(3);
            } else if (IS_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(2);
            }

            return Introspector.decapitalize(getter);
        } catch (ReflectiveOperationException var4) {
            throw new ReflectionOperationException(var4);
        }
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    @Data
    public static class FieldSplitRule {
        /** 分割-属性名 */
        private String ruleFieldName;

        /** 分割-长度 */
        private int ruleCutLength;
    }

    @Accessors(chain = true)
    @Data
    private static class FieldWrapper<T> {
        /** 对象 */
        private T object;

        private FieldSplitRule fieldSplitRule;

        /** 分割后的数组 */
        private String[] arr;

        private FieldWrapper() {

        }

        private FieldWrapper(FieldSplitRule fieldSplitRule, T object) {
            this.fieldSplitRule = fieldSplitRule;
            this.object = object;
            this.arr = cutStrValue(object);
        }

        private String getFieldName() {
            return fieldSplitRule.getRuleFieldName();
        }

        /**
         * @return 属性值
         **/
        private Object getFieldValue(T object) {
            return ReflectUtil.getFieldValue(object, fieldSplitRule.getRuleFieldName());
        }

        /**
         * 分割字段内容
         * @return 分割后的内容列表
         **/
        private String[] cutStrValue(T object) {
            Object fieldValue = getFieldValue(object);
            if(fieldValue == null) {
                return new String[0];
            }
            if(!(fieldValue instanceof String)) {
                throw new RuntimeException("类型不是字符串");
            }
            String[] arr = StringUtil.cut(String.valueOf(fieldValue), fieldSplitRule.getRuleCutLength());
            setArr(arr);
            return arr;
        }


    }

    public interface MyFn<T, R> extends Function<T, R>, Serializable {
    }

}

 

posted @ 2024-04-30 16:34  Peter.Jones  阅读(7)  评论(0编辑  收藏  举报