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

com.alilitech.util.BeanUtils Maven / Gradle / Ivy

There is a newer version: 2.1.3
Show newest version
/*
 *    Copyright 2017-2021 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.alilitech.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.beans.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.temporal.Temporal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * bean utils
 * copy properties contains parent's properties, aggregate object's properties. And also open a cache.
 * @author zhouxiaxiang
 *
 */
public class BeanUtils {

	/** Log */
	private static final Logger logger = LoggerFactory.getLogger(BeanUtils.class);

	/** cache */
	private static final Map, List> cache = new ConcurrentHashMap<>();

	/**
	 * bean to map,only support the fields of the current class
	 * @param source source object
	 * @return map result
	 */
	public static Map beanToMapCommon(Object source) {
		if(source == null) {
			logger.debug("Source object is null");
			return null;
		}
		Map mapRet = new HashMap<>();
		List list = BeanUtils.findSourceMethod(source);
		try {
			for (TempBean tb : list) {
//				try {
					Object value = tb.fieldDesc.getterMethod.invoke(tb.object);
					String fieldName = tb.fieldDesc.fieldName;
					mapRet.put(fieldName, value);
//				} catch ( SecurityException e) {
//					logger.debug(tb.getFieldDesc().getSetName() + " is not exist, not covert!");
//				}
			}
		} catch (Throwable e) {
			logger.error("copy occur error", e);
		}
		return mapRet;
	}

	/**
	 * bean to map,also support the field of the parent class
	 * @param source source object
	 * @return map result
	 */
	public static Map beanToMap(Object source) {
		if(source == null) {
			logger.debug("Source object is null");
			return null;
		}
		Map mapRet = new HashMap<>();
		try {
			List list = BeanUtils.findSourceMethod(source, null);
			for (TempBean tb : list) {
//				try {
					Object value = tb.fieldDesc.getterMethod.invoke(tb.object);
					String fieldName = tb.fieldDesc.fieldName;
					mapRet.put(fieldName, value);
//				} catch (SecurityException e) {
//					logger.debug(tb.getFieldDesc().getSetName() + " is not exist, not covert!");
//				}
			}
		} catch (Throwable e) {
			logger.error("copy occur error", e);
		}
		return mapRet;
	}

	/**
	 * 将源list属性拷贝成目标list
	 * @param source 源list
	 * @param clazz 目标list对象的类
	 * @return 新的集合
	 */
	public static  List copyPropertiesList(List source, Class clazz, String... ignoreProperties)  {
		List listRet = new ArrayList<>();
		if(!CollectionUtils.isEmpty(source)) {
			// 解析需要忽略的字段
			IgnoreProperty[] ignorePropertyArray = resolveIgnoreProperties(source.getClass().getSimpleName(), ignoreProperties);
			for (Object o : source) {
				listRet.add(copyPropertiesDeep(o, clazz, ignorePropertyArray));
			}
		} else {
			logger.debug("Source List is empty");
		}
		return listRet;
	}

	/**
	 * support DK1.8 {@link Optional}
	 */
	public static  Optional copyPropertiesDeep(Optional source, Class clazz, String... ignoreProperties) {
		if(source.isPresent()) {
			T t = copyPropertiesDeep(source.get(), clazz, ignoreProperties);
			return Optional.ofNullable(t);
		} else {
			return Optional.empty();
		}
	}

	/**
	 * 将源对象的属性(包括聚合对象)拷贝到目标对象,目标对象必须为没有聚合的对象
	 * @param source 源对象
	 * @param clazz 目标对象类
	 * @return 新的对象
	 */
	public static  T copyPropertiesDeep(Object source, Class clazz, String... ignoreProperties)  {
		if(source == null) {
			return null;
		}

		T target = null;
		try {
			target = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			logger.error("Instance target object error!");
		}
		// 解析需要忽略的字段
		IgnoreProperty[] ignorePropertyArray = resolveIgnoreProperties(source.getClass().getSimpleName(), ignoreProperties);
		copyPropertiesDeep(source, target, ignorePropertyArray);
		return target;
	}

	private static  T copyPropertiesDeep(Object source, Class clazz, IgnoreProperty... ignoreProperties)  {
		if(source == null) {
			return null;
		}

		T target = null;
		try {
			target = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			logger.error("Instance target object error!");
		}
		copyPropertiesDeep(source, target, ignoreProperties);
		return target;
	}

	/**
	 * 将源对象的属性(包括聚合对象)拷贝到目标对象,目标对象必须为没有聚合的对象
	 * @param source 源对象
	 * @param target 目标对象,不能为空
	 * @param ignoreProperties 需要忽略的源对象类的字段格式为 比如  [类的简单名称(simpleName).]fieldName),simpleName 可以忽略表示最外层的类
	 */
	public static void copyPropertiesDeep(Object source, Object target, String... ignoreProperties) {
		if(target == null) {
			logger.debug("Target object is null");
			return;
		}
		if(source == null) {
			logger.debug("Source object is null");
			return;
		}
		// 解析需要忽略的字段
		IgnoreProperty[] ignorePropertyArray = resolveIgnoreProperties(source.getClass().getSimpleName(), ignoreProperties);
		copyPropertiesDeep(source, target, ignorePropertyArray);
	}

	/**
	 * 将源对象的属性(包括聚合对象)拷贝到目标对象,目标对象必须为没有聚合的对象
	 * @param target 目标对象,不能为空
	 * @param source 源对象
	 */
	private static void copyPropertiesDeep(Object source, Object target, IgnoreProperty... ignoreProperties) {
		try {
			Map tbSourceMap = BeanUtils.findSourceMethodAndTranslateGetNameMap(source, ignoreProperties);
			List listTarget = BeanUtils.findSourceMethod(target, null);
			for (TempBean tempBeanTarget : listTarget) {
				//查找源对象的get方法
				TempBean tempBeanSource = tbSourceMap.get(tempBeanTarget.fieldDesc.getterName);
				//若不存在,则直接跳过
				if (tempBeanSource == null) {
					continue;
				}
				Method setterMethod = tempBeanTarget.fieldDesc.setterMethod;
				Object value = tempBeanSource.fieldDesc.getterMethod.invoke(tempBeanSource.object);
				//值为空不需要塞
				if (value == null) {
					continue;
				}
				setterMethod.invoke(target, value);
			}
		} catch (Throwable e) {
			logger.error("copy occur error", e);
		}
	}

	/**
	 * 查找对象源的get和set方法,包括聚合对象, 并转换成以get方法为key的Map
	 */
	protected static Map findSourceMethodAndTranslateGetNameMap(Object source, IgnoreProperty... ignoreProperties) throws Exception {
		List list = BeanUtils.findSourceMethod(source, null);
		Map retMap = new HashMap<>();

		// 区分是否有过滤的属性
		if(ignoreProperties == null || ignoreProperties.length == 0) {
			for(TempBean tb : list) {
				retMap.put(tb.fieldDesc.getterName, tb);
			}
		} else {
			for(TempBean tb : list) {
				boolean flag = false;
				for(IgnoreProperty ignoreProperty : ignoreProperties) {
					if(ignoreProperty.equalsWith(tb.objectSimpleName, tb.fieldDesc.fieldName)) {
						flag = true;
						break;
					}
				}
				if(flag) {
					continue;
				}
				retMap.put(tb.fieldDesc.getterName, tb);
			}
		}

		return retMap;
	}

	protected static IgnoreProperty[] resolveIgnoreProperties(String simpleName, String... ignoreProperties) {
		if(ignoreProperties == null || ignoreProperties.length == 0) {
			return null;
		}

		IgnoreProperty[] ignorePropertyArray = new IgnoreProperty[ignoreProperties.length];
		for(int i=0; i findSourceMethod(Object source, List list) throws Exception {
		if(list == null) {
			list = new ArrayList<>();
		}

		Class clazzSource = source.getClass();

		List descList = new ArrayList<>();

		if(cache.containsKey(source.getClass())) {
			descList = cache.get(source.getClass());
		} else {

			List sourceFields = getAllFields(clazzSource, null);

			for (Field field : sourceFields) {
				if (isDirectConvert(field.getType())) {
					descList.add(new FieldDesc(field));
					continue;
				}
				if (!Collection.class.isAssignableFrom(field.getType())) {
					descList.add(new FieldDesc(field));
				}
			}

			cache.put(source.getClass(), descList);
		}

		for(FieldDesc fieldDesc : descList) {

			if(isDirectConvert(fieldDesc.type)) {
//				TempBean tempBean = new TempBean(fieldDesc, source);
				list.add(new TempBean(fieldDesc, source));
			} else {
//				Field field = source.getClass().getDeclaredField(fieldDesc.getFieldName());
				Object nextO = getFieldObject(fieldDesc, source);
				if (nextO != null) {
					findSourceMethod(nextO, list);
				}
			}
		}

		return list;
	}

	/**
	 * 只取类的第一层,不包括对象里的对象
	 */
	protected static List findSourceMethod(Object source) {
		List list = new ArrayList<>();
		Class clazzSource = source.getClass();
		List sourceFields = getAllFields(clazzSource, null);

		for (Field field : sourceFields) {
			list.add(new TempBean(new FieldDesc(field), source));
		}
		return list;
	}

	private static boolean isDirectConvert(Class clazz) {
		return clazz.isPrimitive() ||
				String.class.equals(clazz) ||
				Number.class.isAssignableFrom(clazz) ||
				Boolean.class.equals(clazz) ||
				Date.class.isAssignableFrom(clazz) ||
				Temporal.class.isAssignableFrom(clazz) ||
				Character.class.equals(clazz) ||
				clazz.isEnum() ||
				Class.class.equals(clazz);
	}

	/**
	 * 获得类的所有字段,包括父级字段
	 */
	private static List getAllFields(Class clazz, List list) {
		if(list == null) {
			list = new ArrayList<>();
		}
		Field[] fields = clazz.getDeclaredFields();
		for(Field field : fields) {
			if(!field.isAnnotationPresent(Transient.class)) {
				list.add(field);
			}
		}
		if(!"Object".equals(clazz.getSuperclass().getSimpleName())) {
			getAllFields(clazz.getSuperclass(), list);
		}

		return list;
	}

	/**
	 * 根据对象和字段名获得这个字段的对象值
	 */
	private static Object getFieldObject(FieldDesc fieldDesc, Object source) throws InvocationTargetException, IllegalAccessException {
		Method method = fieldDesc.getterMethod;
		if(method == null) {
			return null;
		}
		return method.invoke(source);
	}

	private static class IgnoreProperty {

		private String simpleName;

		private String property;

		public IgnoreProperty(String simpleName, String property) {
			this.simpleName = simpleName;
			this.property = property;
		}

		public boolean equalsWith(String simpleName, String property) {
			return simpleName.equals(this.simpleName) && property.equals(this.property);
		}
	}

	private static class TempBean {

		private FieldDesc fieldDesc;

		private Object object;

		private String objectSimpleName;

		public TempBean(FieldDesc fieldDesc, Object object) {
			this.fieldDesc = fieldDesc;
			this.object = object;
			this.objectSimpleName = object.getClass().getSimpleName();
		}
	}

	private static class FieldDesc {

		private String fieldName;
		/** getter method name */
		private String getterName;
		/** setter method name */
		private String setterName;
		/** getter method */
		private Method getterMethod;
		/** setter method */
		private Method setterMethod;
		/** type */
		private Class type;

		public FieldDesc(Field field) {
			this.fieldName = field.getName();
			this.getterName = JavaBeansUtil.getGetterMethodName(fieldName, field.getType().getSimpleName());
			this.setterName = JavaBeansUtil.getSetterMethodName(fieldName);

			try {
				getterMethod = field.getDeclaringClass().getMethod(getterName);
				setterMethod = field.getDeclaringClass().getMethod(setterName, field.getType());
			} catch (NoSuchMethodException e) {
				logger.error("Do not find getter or setter method for the field '{}' of the Class '{}'", this.fieldName, field.getDeclaringClass().getName());
			}

			this.type = field.getType();
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy