All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cool.linco.common.convert.ObjectRender Maven / Gradle / Ivy

The newest version!
package cool.linco.common.convert;

import javax.lang.model.type.NullType;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class ObjectRender {

    private static volatile ObjectRender objectRender;

    private String valueSuffix = "Value";

    private AbstractDictContainer dictContainer;

    private ObjectRender(AbstractDictContainer dictContainer) {
        this.dictContainer = dictContainer;
    }

    /**
     * 使用自定义缓存容器入Redis
     *
     * @param valueSuffix   新值字段名增加前缀
     * @param dictContainer 取值字典
     * @return 渲染器对象
     */
    public static ObjectRender getInstance(String valueSuffix, AbstractDictContainer dictContainer) {
        if (objectRender == null) {
            synchronized (ObjectRender.class) {
                if (objectRender == null) {
                    objectRender = new ObjectRender(dictContainer);
                    // 限制修改, 只允许初始化时设值
                    if (valueSuffix != null) {
                        objectRender.valueSuffix = valueSuffix;
                    }
                }
            }
        }
        return objectRender;
    }

    public static ObjectRender getInstance() {
        return getInstance(null, new MemoryDictContainer());
    }


    public static ObjectRender getInstance(String valueSuffix) {
        return getInstance(valueSuffix, new MemoryDictContainer());
    }

    public static ObjectRender getInstance(AbstractDictContainer dictContainer) {
        return getInstance(null, dictContainer);
    }


    public void addDict(String key, Map values) {
        dictContainer.addDict(key, values);
    }

    public void addDict(String dict, String key, String value, Collection source) {
        dictContainer.addDict(dict, key, value, source);
    }

    /**
     * 如果未启用自动过期的中间件或需要立即生效, 修改数据时需要调用这个方法手动更新, 新增则不需要
     * 重新加载key可以用value=null, 要求字典配置已提供addDictItemSource
     * 删除key要求数据源和传入value都为null
     */
    public void setValue(String dict, String key, Object value) {
        dictContainer.setValue(dict, key, value);
    }

    public List> render(Collection objectList) {
        List> resultList = new ArrayList<>(objectList.size());
        for (Object object : objectList) {
            Map resultMap = render(object);
            resultList.add(resultMap);
        }
        return resultList;
    }

    public  List render(Collection objectList, Class clazz) {
        List resultList = new ArrayList<>(objectList.size());
        for (Object object : objectList) {
            T t = render(object, clazz);
            resultList.add(t);
        }
        return resultList;
    }


    /**
     * 如果某些项不需要定义规则的渲染方式, RenderRule使用Null
     */
    public List> render(Collection objectList, Map renderRuleMap) {
        List> resultList = new ArrayList<>(objectList.size());
        for (Object object : objectList) {
            Map resultMap = render(object, renderRuleMap);
            resultList.add(resultMap);
        }
        return resultList;
    }

    /**
     * 渲染为指定类型列表
     * 如果某些项不需要定义规则的渲染方式, RenderRule使用Null
     */
    public  List render(Collection objectList, Class clazz, Map renderRuleMap) {
        List resultList = new ArrayList<>(objectList.size());
        for (Object object : objectList) {
            T t = render(object, clazz, renderRuleMap);
            resultList.add(t);
        }
        return resultList;
    }

    /**
     * 最简渲染
     * 未指定渲染规则时, dict=key
     */
    public Map render(Object object) {
        Map resultMap = ObjectMapUtils.objectToMap(object);
        Map tempMap = new TreeMap<>();
        for (Map.Entry entry : resultMap.entrySet()) {
            simpleRenderItem(tempMap, entry.getKey(), Optional.ofNullable(entry.getValue()).map(Object::toString).orElse(null));
        }
        resultMap.putAll(tempMap);
        return resultMap;
    }

    /**
     * 最简渲染
     * 未指定渲染规则时, dict=key
     */
    public  T render(Object oriObj, Class clazz) {
        T renObj;
        Map oriFieldMap;
        Map renFieldMap;
        try {
            renObj = clazz.newInstance();
            // 获取类的所有字段,包括父类字段
            oriFieldMap = getAllFields(oriObj.getClass());
            renFieldMap = getAllFields(renObj.getClass());
            if (renObj instanceof CopyAdapter && checkCopyType(oriObj, renObj)) {
                ((CopyAdapter) renObj).copy(oriObj);
            } else {
                copyProperties(oriObj, oriFieldMap, renObj, renFieldMap);
            }
            for (Map.Entry fieldEntry : oriFieldMap.entrySet()) {
                Object oriFieldValue = oriFieldMap.get(fieldEntry.getKey()).get(oriObj);
                // 只映射基础类型值
                if ((oriFieldValue instanceof String || oriFieldValue instanceof Number)) {
                    simpleRenderItem(renObj, renFieldMap, fieldEntry.getKey(), oriFieldValue.toString());
                }
            }
        } catch (IllegalAccessException | InstantiationException | NoSuchFieldException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        return renObj;
    }

    private void simpleRenderItem(Map resultMap, String dict, String item) {
        if (dictContainer.containsOrConfig(dict)) {
            Object value = dictContainer.getValue(dict, item);
            if (value != null) {
                resultMap.put(dict + valueSuffix, value);
            }
        }
    }

    private  void simpleRenderItem(T renObj, Map renFieldMap, String dict, String item) throws NoSuchFieldException, IllegalAccessException {
        // 优先判断目标字段, 一般是不存在的
        Field field = renFieldMap.get(dict + valueSuffix);
        if (field != null) {
            if (dictContainer.containsOrConfig(dict)) {
                Object value = dictContainer.getValue(dict, item);
                if (value != null) {
                    field.setAccessible(true);
                    field.set(renObj, value);
                }
            }
        }
    }

    /**
     * @param object        待渲染数据源
     * @param renderRuleMap String:渲染的字段名, RenderRule: 字典名, 渲染结果名
     *                      字段符合key则启用渲染, 有rule按规则, 否则按简单渲染
     * @return 渲染结果map
     */
    public Map render(Object object, Map renderRuleMap) {
        Map resultMap = ObjectMapUtils.objectToMap(object);
        for (Map.Entry ruleEntry : renderRuleMap.entrySet()) {
            Object itemKey = resultMap.get(ruleEntry.getValue().getKeyField());
            if (itemKey != null) {
                // 只映射基础类型值
                if ((itemKey instanceof String || itemKey instanceof Number)) {
                    ruleRenderItem(resultMap, ruleEntry, itemKey.toString());
                }
            }
        }
        return resultMap;
    }



	/**
	 * 渲染对象
	 * @param oriObj        待渲染数据源
	 * @param renderRuleMap String:渲染的字段名, RenderRule: 字典名, 渲染结果名
	 * @return 渲染结果map
	 */
/*	public  T render(Object oriObj, Class clazz, Map renderRuleMap) {
		T renObj;
		Map oriFieldMap;
		Map renFieldMap;
		try {
			renObj = clazz.newInstance();
			// 获取类的所有字段,包括父类字段
			oriFieldMap = getAllFields(oriObj.getClass());
			renFieldMap = getAllFields(renObj.getClass());
			copyProperties(oriObj, oriFieldMap, renObj, renFieldMap);
			for (Map.Entry ruleEntry : renderRuleMap.entrySet()) {
				Object oriFieldValue = oriFieldMap.get(ruleEntry.getValue().getKeyField()).get(oriObj);
				if (oriFieldValue != null) {
					if (oriFieldValue instanceof String || oriFieldValue instanceof Number) {
						ruleRenderItem(renObj, renFieldMap, ruleEntry, oriFieldValue.toString());
					}
				}
			}
		} catch (IllegalAccessException | InstantiationException | NoSuchFieldException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		return renObj;
	}

	public > T renderAdapter(R oriObj, Class clazz, Map renderRuleMap) {
		T renObj;
		Map oriFieldMap;
		Map renFieldMap;
		try {
			renObj = clazz.newInstance();
			// 获取类的所有字段,包括父类字段
			oriFieldMap = getAllFields(oriObj.getClass());
			renFieldMap = getAllFields(renObj.getClass());
			if (checkCopyType(oriObj, renObj)) {
				// 实现copy且泛型类型匹配
				renObj.copy(oriObj);
			} else {
				copyProperties(oriObj, oriFieldMap, renObj, renFieldMap);
			}
			for (Map.Entry ruleEntry : renderRuleMap.entrySet()) {
				Object oriFieldValue = oriFieldMap.get(ruleEntry.getValue().getKeyField()).get(oriObj);
				if (oriFieldValue != null) {
					if (oriFieldValue instanceof String || oriFieldValue instanceof Number) {
						ruleRenderItem(renObj, renFieldMap, ruleEntry, oriFieldValue.toString());
					}
				}
			}
		} catch (IllegalAccessException | InstantiationException | NoSuchFieldException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		return renObj;
	}*/
    public  T render(Object oriObj, Class clazz, Map renderRuleMap) {
        try {
            return renderCommonLogic(oriObj, clazz, renderRuleMap, null);
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

	/**
	 * 通过adapter渲染对象
	 * @param oriObj        待渲染数据源
	 * @param renderRuleMap String:渲染的字段名, RenderRule: 字典名, 渲染结果名
	 * @return 渲染结果map
	 */
    public > T renderAdapter(R oriObj, Class clazz, Map renderRuleMap) {
        try {
            BiConsumer copyAdapterAction = (original, target) -> {
                if (checkCopyType(original, target)) {
                    target.copy(original);
                }
            };
            return renderCommonLogic(oriObj, clazz, renderRuleMap, copyAdapterAction);
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }


	private  T renderCommonLogic(O oriObj, Class clazz, Map renderRuleMap, BiConsumer copyAction)
			throws IllegalAccessException, InstantiationException, NoSuchFieldException {
		T renObj = clazz.newInstance();
		Map oriFieldMap = getAllFields(oriObj.getClass());
		Map renFieldMap = getAllFields(renObj.getClass());

		if (copyAction != null) {
			copyAction.accept(oriObj, renObj);
		} else {
			copyProperties(oriObj, oriFieldMap, renObj, renFieldMap);
		}

		for (Map.Entry ruleEntry : renderRuleMap.entrySet()) {
			Object oriFieldValue = oriFieldMap.get(ruleEntry.getValue().getKeyField()).get(oriObj);
			if (oriFieldValue instanceof String || oriFieldValue instanceof Number) {
				ruleRenderItem(renObj, renFieldMap, ruleEntry, oriFieldValue.toString());
			}
		}
		return renObj;
	}

    private void ruleRenderItem(Map resultMap, Map.Entry ruleEntry, String item) {
        if (dictContainer.containsOrConfig(ruleEntry.getKey())) {
            RenderRule rule = ruleEntry.getValue();
            Object value = dictContainer.getValue(ruleEntry.getKey(), item);
            if (value != null) {
                resultMap.put(rule.getRenderField(), value);
            }
        }
    }

    private  void ruleRenderItem(T renObj, Map renFieldMap, Map.Entry ruleEntry, String item) throws IllegalAccessException, NoSuchFieldException {
        if (dictContainer.containsOrConfig(ruleEntry.getKey())) {
            RenderRule rule = ruleEntry.getValue();
            Object value = dictContainer.getValue(ruleEntry.getKey(), item);
            if (value != null) {
                Field field = renFieldMap.get(rule.getRenderField());
                if (field != null) {
                    field.setAccessible(true);
                    field.set(renObj, value);
                }
            }
        }
    }

    public void addDictSource(String dict, String keyField, String valueField, Function> getDictFunction) {
        dictContainer.addDictSource(dict, keyField, valueField, getDictFunction);
    }

    public void addDictItemSource(String dict, Function getItemFunction) {
        dictContainer.addDictItemSource(dict, getItemFunction);
    }

    /**
     * 对象同名属性赋值
     */
    public static  void copyProperties(S source, Map oriFieldMap, T target, Map tarFieldMap) throws IllegalAccessException {
        if (source == null || target == null) {
            throw new IllegalArgumentException("Source or target cannot be null.");
        }

        for (Field targetField : tarFieldMap.values()) {

            if (oriFieldMap.containsKey(targetField.getName())) {
                Field sourceField = oriFieldMap.get(targetField.getName());
                if (targetField.getType().isAssignableFrom(sourceField.getType())) {
                    targetField.setAccessible(true);
                    targetField.set(target, sourceField.get(source));
                }
                // 跳过类型不匹配的字段
            }
        }
    }

    private static Map getAllFields(Class clazz) {
        Map fieldsMap = new HashMap<>();
        while (clazz != null && clazz != Object.class) {
            for (Field field : clazz.getDeclaredFields()) {
                // 排除静态和终态字段
                if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())) {
                    field.setAccessible(true);
                    // 子类属性优先
                    fieldsMap.putIfAbsent(field.getName(), field);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return fieldsMap;
    }

    private static boolean checkCopyType(Object oriObj, Object renObj) {
        Type genericType = renObj.getClass().getGenericSuperclass();
        if (genericType instanceof ParameterizedType) {
            Type typeArg = ((ParameterizedType) genericType).getActualTypeArguments()[0];
            if (oriObj.getClass().isAssignableFrom((Class) typeArg)) {
                return true;
            }
        }
        return false;
    }

}


/*
* pageHelper下封装使用示例:
	private PageResult(Page page, NullType non) {
		this.pageSize = page.getPageSize();
		this.totalPage = page.getPages();
		this.total = page.getTotal();
		this.pageNum = page.getPageNum();
	}

	public static  PageResult of (Page page, Function, List> fixFunction){
		PageResult pageResult = new PageResult<>(page, null);
		pageResult.data = fixFunction.apply(page.getResult());
		return pageResult;
	}
	*
	*
	* 使用
	return PageResult.of(service.queryPage(), objectRender::render);
	return PageResult.of(service.queryPage(), (list)->
		objectRender.render(list, ObjectRenderConst.renderRuleMap));
* */




© 2015 - 2025 Weber Informatics LLC | Privacy Policy