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 {
}
}