package cn.orm.sqltoy.utils;

import static java.lang.System.err;

import java.io.BufferedReader;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Array;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import cn.orm.sqltoy.callback.ReflectPropsHandler;
import cn.orm.sqltoy.config.annotation.Entity;
import cn.orm.sqltoy.config.annotation.OneToMany;
import cn.orm.sqltoy.config.annotation.OneToOne;
import cn.orm.sqltoy.config.annotation.SqlToyEntity;
import cn.orm.sqltoy.config.model.DataType;
import cn.orm.sqltoy.config.model.EntityMeta;
import cn.orm.sqltoy.config.model.KeyAndIndex;
import cn.orm.sqltoy.config.model.TableCascadeModel;
import cn.orm.sqltoy.exception.DataAccessException;
import cn.orm.sqltoy.model.IgnoreKeyCaseMap;
import cn.orm.sqltoy.plugins.TypeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @project sagacity-sqltoy
 * @description 类处理通用工具,提供反射处理
 * @author zhongxuchen
 * @version v1.0,Date:2008-11-10
 * @modify data:2019-09-05 优化匹配方式，修复setIsXXX的错误
 * @modify data:2020-06-23 优化convertType(Object, String) 方法
 * @modify data:2020-07-08 修复convertType(Object, String) 转Long类型时精度丢失问题
 * @modify data:2021-03-12 支持property中含下划线跟对象方法进行匹配
 * @modify data:2022-10-19
 *         convertType类型匹配改成int类型的匹配,通过DataType将TypeName转化为int，批量时效率大幅提升
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class BeanUtil {
	/**
	 * 定义日志
	 */
	protected final static Logger logger = LoggerFactory.getLogger(BeanUtil.class);

	public final static Pattern ARRAY_PATTERN = Pattern.compile("\\[\\d+\\]$");

	/**
	 * 保存set方法
	 */
	private static ConcurrentHashMap<String, Method> setMethods = new ConcurrentHashMap<String, Method>();

	/**
	 * 保存get方法
	 */
	private static ConcurrentHashMap<String, Method> getMethods = new ConcurrentHashMap<String, Method>();

	// 保存pojo的级联关系
	private static ConcurrentHashMap<String, List> cascadeModels = new ConcurrentHashMap<String, List>();

	// 静态方法避免实例化和继承
	private BeanUtil() {

	}

	/**
	 * <p>
	 * <li>update 2019-09-05 优化匹配方式，修复setIsXXX的错误</li>
	 * <li>update 2020-04-09 支持setXXX()并返回对象本身,适配链式操作</li>
	 * <li>update 2021-03-12 支持property中含下划线跟对象属性进行匹配</li>
	 * </p>
	 * 
	 * @todo 获取指定名称的方法集
	 * @param voClass
	 * @param props
	 * @return
	 */
	public static Method[] matchSetMethods(Class voClass, String... props) {
		int indexSize = props.length;
		Method[] result = new Method[indexSize];
		Method[] methods = voClass.getMethods();
		// 先过滤出全是set且只有一个参数的方法
		List<Method> realMeth = new ArrayList<Method>();
		for (Method mt : methods) {
			// 剔除void 判断条件，存在: this setxxxx(){this.xxx=xxx;return this;}场景
			// if (mt.getParameterTypes().length == 1 &&
			// void.class.equals(mt.getReturnType())) {
			if (mt.getParameterTypes().length == 1) {
				if (mt.getName().startsWith("set")) {
					realMeth.add(mt);
				}
			}
		}
		if (realMeth.isEmpty()) {
			return result;
		}
		Method method;
		String prop;
		boolean matched = false;
		String name;
		Class type;
		String minProp;
		Method underlinMethod;
		int meter = 0;
		boolean isBool;
		int index;
		for (int i = 0; i < indexSize; i++) {
			if (props[i] != null) {
				prop = "set".concat(props[i].toLowerCase());
				matched = false;
				// 将属性名称剔除下划线
				minProp = null;
				if (prop.contains("_")) {
					minProp = prop.replace("_", "");
				}
				meter = 0;
				underlinMethod = null;
				index = 0;
				for (int j = 0; j < realMeth.size(); j++) {
					isBool = false;
					method = realMeth.get(j);
					name = method.getName().toLowerCase();
					// setXXX完全匹配(优先匹配无下划线)
					if (prop.equals(name)) {
						matched = true;
					} else {
						// boolean 类型参数
						type = method.getParameterTypes()[0];
						isBool = (type.equals(Boolean.class) || type.equals(boolean.class)) && prop.startsWith("setis");
						if (isBool && prop.replaceFirst("setis", "set").equals(name)) {
							matched = true;
						}
					}
					// 匹配属性含下划线场景
					if (!matched && minProp != null) {
						if (minProp.equals(name) || (isBool && minProp.replaceFirst("setis", "set").equals(name))) {
							meter++;
							underlinMethod = method;
							index = j;
						}
					}
					if (matched) {
						result[i] = method;
						result[i].setAccessible(true);
						realMeth.remove(j);
						break;
					}
				}
				// 属性剔除下划线后存在唯一匹配
				if (!matched && meter == 1) {
					result[i] = underlinMethod;
					result[i].setAccessible(true);
					realMeth.remove(index);
				}
				if (realMeth.isEmpty()) {
					break;
				}
			}
		}
		return result;
	}

	/**
	 * @todo 获取指定名称的方法集,不区分大小写
	 * @param voClass
	 * @param props
	 * @return
	 */
	public static Method[] matchGetMethods(Class voClass, String... props) {
		Method[] methods = voClass.getMethods();
		List<Method> realMeth = new ArrayList<Method>();
		String name;
		// 过滤get 和is 开头的方法
		for (Method mt : methods) {
			if (!void.class.equals(mt.getReturnType()) && mt.getParameterTypes().length == 0) {
				name = mt.getName().toLowerCase();
				if (name.startsWith("get") || name.startsWith("is")) {
					realMeth.add(mt);
				}
			}
		}
		int indexSize = props.length;
		Method[] result = new Method[indexSize];
		if (realMeth.isEmpty()) {
			return result;
		}
		String prop;
		Method method;
		boolean matched = false;
		Class type;
		String minProp;
		Method underlinMethod;
		int meter = 0;
		boolean isBool;
		int index;
		for (int i = 0; i < indexSize; i++) {
			if (props[i] != null) {
				prop = props[i].toLowerCase();
				matched = false;
				// 将属性名称剔除下划线
				minProp = null;
				if (prop.contains("_")) {
					minProp = prop.replace("_", "");
				}
				meter = 0;
				underlinMethod = null;
				index = 0;
				for (int j = 0; j < realMeth.size(); j++) {
					isBool = false;
					method = realMeth.get(j);
					name = method.getName().toLowerCase();
					// get完全匹配
					if (name.equals("get".concat(prop))) {
						matched = true;
					} else {
						// boolean型 is开头的方法
						type = method.getReturnType();
						isBool = name.startsWith("is") && (type.equals(Boolean.class) || type.equals(boolean.class));
						if (isBool && (name.equals(prop) || name.equals("is".concat(prop)))) {
							matched = true;
						}
					}
					// 匹配属性含下划线场景
					if (!matched && minProp != null) {
						if (name.equals("get".concat(minProp))
								|| (isBool && (name.equals(minProp) || name.equals("is".concat(minProp))))) {
							meter++;
							underlinMethod = method;
							index = j;
						}
					}
					if (matched) {
						result[i] = method;
						result[i].setAccessible(true);
						realMeth.remove(j);
						break;
					}
				}
				// 属性剔除下划线后存在唯一匹配
				if (!matched && meter == 1) {
					result[i] = underlinMethod;
					result[i].setAccessible(true);
					realMeth.remove(index);
				}
				if (realMeth.isEmpty()) {
					break;
				}
			}
		}
		return result;
	}

	/**
	 * @todo 获取指定名称的方法集,不区分大小写
	 * @param voClass
	 * @param properties
	 * @return
	 */
	public static Integer[] matchMethodsType(Class voClass, String... properties) {
		if (properties == null || properties.length == 0) {
			return null;
		}
		int indexSize = properties.length;
		Method[] methods = voClass.getMethods();
		Integer[] fieldsType = new Integer[indexSize];
		String methodName;
		String typeName;
		int methodCnt = methods.length;
		String property;
		Method method;
		for (int i = 0; i < indexSize; i++) {
			fieldsType[i] = java.sql.Types.NULL;
			property = properties[i].toLowerCase();
			for (int j = 0; j < methodCnt; j++) {
				method = methods[j];
				methodName = method.getName().toLowerCase();
				// update 2012-10-25 from equals to ignoreCase
				if (!void.class.equals(method.getReturnType()) && method.getParameterTypes().length == 0
						&& (methodName.equals("get".concat(property)) || methodName.equals("is".concat(property))
								|| (methodName.startsWith("is") && methodName.equals(property)))) {
					typeName = method.getReturnType().getSimpleName().toLowerCase();
					if ("string".equals(typeName)) {
						fieldsType[i] = java.sql.Types.VARCHAR;
					} else if ("integer".equals(typeName)) {
						fieldsType[i] = java.sql.Types.INTEGER;
					} else if ("bigdecimal".equals(typeName)) {
						fieldsType[i] = java.sql.Types.DECIMAL;
					} else if ("date".equals(typeName)) {
						fieldsType[i] = java.sql.Types.DATE;
					} else if ("timestamp".equals(typeName)) {
						fieldsType[i] = java.sql.Types.TIMESTAMP;
					} else if ("int".equals(typeName)) {
						fieldsType[i] = java.sql.Types.INTEGER;
					} else if ("long".equals(typeName)) {
						fieldsType[i] = java.sql.Types.NUMERIC;
					} else if ("double".equals(typeName)) {
						fieldsType[i] = java.sql.Types.DOUBLE;
					} else if ("clob".equals(typeName)) {
						fieldsType[i] = java.sql.Types.CLOB;
					} else if ("biginteger".equals(typeName)) {
						fieldsType[i] = java.sql.Types.BIGINT;
					} else if ("blob".equals(typeName)) {
						fieldsType[i] = java.sql.Types.BLOB;
					} else if ("byte[]".equals(typeName)) {
						fieldsType[i] = java.sql.Types.BINARY;
					} else if ("boolean".equals(typeName)) {
						fieldsType[i] = java.sql.Types.BOOLEAN;
					} else if ("char".equals(typeName)) {
						fieldsType[i] = java.sql.Types.CHAR;
					} else if ("number".equals(typeName)) {
						fieldsType[i] = java.sql.Types.NUMERIC;
					} else if ("short".equals(typeName)) {
						fieldsType[i] = java.sql.Types.NUMERIC;
					} else if ("float".equals(typeName)) {
						fieldsType[i] = java.sql.Types.FLOAT;
					} else if ("datetime".equals(typeName)) {
						fieldsType[i] = java.sql.Types.DATE;
					} else if ("time".equals(typeName)) {
						fieldsType[i] = java.sql.Types.TIME;
					} else if ("byte".equals(typeName)) {
						fieldsType[i] = java.sql.Types.TINYINT;
					} else if (typeName.endsWith("[]")) {
						fieldsType[i] = java.sql.Types.ARRAY;
					} else {
						fieldsType[i] = java.sql.Types.NULL;
					}
					break;
				}
			}
		}
		return fieldsType;
	}

	/**
	 * @todo 类的方法调用
	 * @param bean
	 * @param methodName
	 * @param args
	 * @return
	 * @throws Exception
	 */
	public static Object invokeMethod(Object bean, String methodName, Object[] args) throws Exception {
		try {
			Method method = getMethod(bean.getClass(), methodName, args == null ? 0 : args.length);
			if (method == null) {
				return null;
			}
			return method.invoke(bean, args);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * @todo <b>对象比较</b>
	 * @param target
	 * @param compared
	 * @return
	 */
	public static boolean equals(Object target, Object compared) {
		if (null == target) {
			return target == compared;
		}
		return target.equals(compared);
	}

	/**
	 * @todo 用于不同类型数据之间进行比较，判断是否相等,当类型不一致时统一用String类型比较
	 * @param target
	 * @param compared
	 * @param ignoreCase
	 * @return
	 */
	public static boolean equalsIgnoreType(Object target, Object compared, boolean ignoreCase) {
		if (target == null || compared == null) {
			return target == compared;
		}
		if (target.getClass().equals(compared.getClass()) && !(target instanceof CharSequence)) {
			return target.equals(compared);
		}
		if (ignoreCase) {
			return target.toString().equalsIgnoreCase(compared.toString());
		}
		return target.toString().equals(compared.toString());
	}

	/**
	 * @TODO 比较两个对象的大小
	 * @param target
	 * @param compared
	 * @return
	 */
	public static int compare(Object target, Object compared) {
		if (null == target && null == compared) {
			return 0;
		}
		if (null == target) {
			return -1;
		}
		if (null == compared) {
			return 1;
		}

		// 直接相等
		if (target.equals(compared)) {
			return 0;
		}
		// 日期类型
		if ((target instanceof Date || target instanceof LocalDate || target instanceof LocalTime
				|| target instanceof LocalDateTime)
				|| (compared instanceof Date || compared instanceof LocalDate || compared instanceof LocalTime
						|| compared instanceof LocalDateTime)) {
			return DateUtil.convertDateObject(target).compareTo(DateUtil.convertDateObject(compared));
		} // 数字
		else if ((target instanceof Number) || (compared instanceof Number)) {
			return new BigDecimal(target.toString()).compareTo(new BigDecimal(compared.toString()));
		} else {
			return target.toString().compareTo(compared.toString());
		}
	}

	/**
	 * @TODO 提供对象get/set 类型转换
	 * @param value
	 * @param typeValue DataType.getType(typeName) 注意typeName不用转小写
	 * @param typeName  getParameterTypes()[0].getTypeName() 没有转大小写
	 * @return
	 * @throws Exception
	 */
	public static Object convertType(Object value, int typeValue, String typeName) throws Exception {
		return convertType(null, value, typeValue, typeName, null);
	}

	/**
	 * @todo 类型转换 2022-10-18 已经完成了优化，减少了不必要的判断
	 * @param typeHandler
	 * @param value
	 * @param typeValue
	 * @param typeName    getTypeName()没有转大小写
	 * @param genericType 泛型类型
	 * @return
	 * @throws Exception
	 */
	public static Object convertType(TypeHandler typeHandler, Object value, int typeValue, String typeName,
			Class genericType) throws Exception {
		Object paramValue = value;
		// 1
		if (paramValue == null) {
			// 1~5 原生数字类型
			if (typeValue >= DataType.primitiveIntType && typeValue <= DataType.primitiveDoubleType) {
				return 0;
			}
			if (DataType.primitiveBooleanType == typeValue) {
				return false;
			}
			if (DataType.primitiveCharType == typeValue) {
				return " ".charAt(0);
			}
			if (DataType.primitiveByteType == typeValue) {
				return Byte.valueOf("0").byteValue();
			}
			return null;
		}
		// 2 value值的类型跟目标类型一致，直接返回
		if (value.getClass().getTypeName().equals(typeName)) {
			return value;
		}
		// 3 针对非常规类型转换，将jdbc获取的字段结果转为java对象属性对应的类型
		if (typeHandler != null) {
			Object result = typeHandler.toJavaType(typeName, genericType, paramValue);
			if (result != null) {
				return result;
			}
		}
		// 4 非数组类型,但传递的参数值是数组类型且长度为1提取出数组中的单一值
		if (paramValue.getClass().isArray() && typeValue < DataType.aryCharType) {
			if (typeValue == DataType.stringType && (paramValue instanceof byte[])) {
				paramValue = new String((byte[]) paramValue);
			} else if (typeValue == DataType.stringType && (paramValue instanceof char[])) {
				paramValue = new String((char[]) paramValue);
			} else {
				Object[] paramAry = CollectionUtil.convertArray(paramValue);
				if (paramAry.length > 1) {
					throw new DataAccessException("不能将长度大于1,类型为:" + paramValue.getClass().getTypeName() + " 的数组转化为:"
							+ typeName + " 类型的值,请检查!");
				}
				paramValue = paramAry[0];
				if (paramValue == null) {
					return null;
				}
			}
		}
		// 5 字符串第一优先
		if (DataType.stringType == typeValue) {
			if (paramValue instanceof java.sql.Clob) {
				java.sql.Clob clob = (java.sql.Clob) paramValue;
				return clob.getSubString((long) 1, (int) clob.length());
			} else if (paramValue instanceof LocalDate) {
				return DateUtil.formatDate(paramValue, "yyyy-MM-dd");
			} else if (paramValue instanceof LocalTime) {
				return DateUtil.formatDate(paramValue, "HH:mm:ss");
			} else if (paramValue instanceof java.util.Date) {
				return DateUtil.formatDate(paramValue, "yyyy-MM-dd HH:mm:ss");
			}
			return paramValue.toString();
		}
		String valueStr = paramValue.toString();
		boolean isBlank = "".equals(valueStr.trim());
		// 6 bigDecimal第二优先
		if (DataType.wrapBigDecimalType == typeValue) {
			if (isBlank) {
				return null;
			}
			return new BigDecimal(convertBoolean(valueStr));
		}
		// 7 Integer第三
		if (DataType.wrapIntegerType == typeValue) {
			if (isBlank) {
				return null;
			}
			return Integer.valueOf(convertBoolean(valueStr).split("\\.")[0]);
		}
		// 8 第四优先
		if (DataType.localDateTimeType == typeValue) {
			if (paramValue instanceof LocalDateTime) {
				return (LocalDateTime) paramValue;
			}
			// 修复oracle.sql.timestamp 转localdatetime的缺陷
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return DateUtil.asLocalDateTime(oracleTimeStampConvert(paramValue));
			}
			return DateUtil.asLocalDateTime(DateUtil.convertDateObject(paramValue));
		}
		// 9 第五
		if (DataType.localDateType == typeValue) {
			if (paramValue instanceof LocalDate) {
				return (LocalDate) paramValue;
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return DateUtil.asLocalDate(oracleDateConvert(paramValue));
			}
			return DateUtil.asLocalDate(DateUtil.convertDateObject(paramValue));
		}
		// 10 第六
		if (DataType.timestampType == typeValue) {
			if (paramValue instanceof java.sql.Timestamp) {
				return (java.sql.Timestamp) paramValue;
			}
			if (paramValue instanceof java.util.Date) {
				return new Timestamp(((java.util.Date) paramValue).getTime());
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return oracleTimeStampConvert(paramValue);
			}
			if (isBlank) {
				return null;
			}
			return new Timestamp(DateUtil.parseString(valueStr).getTime());
		}
		// 11 第7
		if (DataType.wrapLongType == typeValue) {
			if (isBlank) {
				return null;
			}
			// 考虑数据库中存在默认值为0.00 的问题，导致new Long() 报错，因为精度而不用Double.parse(原生long则可以)
			return Long.valueOf(convertBoolean(valueStr).split("\\.")[0]);
		}
		// 12 第8
		if (DataType.primitiveIntType == typeValue) {
			if (isBlank) {
				return 0;
			}
			// 防止小数而不使用Integer.parseInt
			return Double.valueOf(convertBoolean(valueStr)).intValue();
		}
		// 13 第9 字符串转 boolean 型
		if (DataType.wrapBooleanType == typeValue) {
			if ("true".equals(valueStr.toLowerCase()) || "1".equals(valueStr)) {
				return Boolean.TRUE;
			}
			return Boolean.FALSE;
		}
		// 14 第10 字符串转 boolean 型
		if (DataType.primitiveBooleanType == typeValue) {
			if ("true".equals(valueStr.toLowerCase()) || "1".equals(valueStr)) {
				return true;
			}
			return false;
		}
		// 15 第11
		if (DataType.dateType == typeValue) {
			if (paramValue instanceof java.util.Date) {
				return (java.util.Date) paramValue;
			}
			if (paramValue instanceof Number) {
				return new java.util.Date(((Number) paramValue).longValue());
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return oracleDateConvert(paramValue);
			}
			return DateUtil.parseString(valueStr);
		}
		// 16 第12
		if (DataType.wrapBigIntegerType == typeValue) {
			if (isBlank) {
				return null;
			}
			return new BigInteger(convertBoolean(valueStr).split("\\.")[0]);
		}
		// 17 第13
		if (DataType.wrapDoubleType == typeValue) {
			if (isBlank) {
				return null;
			}
			return Double.valueOf(convertBoolean(valueStr));
		}
		// 18 第13
		if (DataType.localTimeType == typeValue) {
			if (paramValue instanceof LocalTime) {
				return (LocalTime) paramValue;
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return DateUtil.asLocalTime(oracleTimeStampConvert(paramValue));
			}
			return DateUtil.asLocalTime(DateUtil.convertDateObject(paramValue));
		}
		// 19
		if (DataType.primitiveLongType == typeValue) {
			if (isBlank) {
				return 0;
			}
			// 防止小数而不使用Long.parseLong
			return Double.valueOf(convertBoolean(valueStr)).longValue();
		}
		// 20
		if (DataType.primitiveDoubleType == typeValue) {
			if (isBlank) {
				return 0;
			}
			return Double.parseDouble(convertBoolean(valueStr));
		}
		// 21 byte数组
		if (DataType.aryByteType == typeValue) {
			if (paramValue instanceof byte[]) {
				return (byte[]) paramValue;
			}
			// blob类型处理
			if (paramValue instanceof java.sql.Blob) {
				java.sql.Blob blob = (java.sql.Blob) paramValue;
				return blob.getBytes(1, (int) blob.length());
			}
			return valueStr.getBytes();
		}
		// 22
		if (DataType.wrapFloatType == typeValue) {
			if (isBlank) {
				return null;
			}
			return Float.valueOf(convertBoolean(valueStr));
		}
		// 23
		if (DataType.primitiveFloatType == typeValue) {
			if (isBlank) {
				return 0;
			}
			return Float.parseFloat(convertBoolean(valueStr));
		}
		// 24
		if (DataType.wrapShortType == typeValue) {
			if (isBlank) {
				return null;
			}
			return Short.valueOf(Double.valueOf(convertBoolean(valueStr)).shortValue());
		}
		// 25
		if (DataType.primitiveShortType == typeValue) {
			if (isBlank) {
				return 0;
			}
			return Double.valueOf(convertBoolean(valueStr)).shortValue();
		}
		// 26
		if (DataType.sqlDateType == typeValue) {
			if (paramValue instanceof java.sql.Date) {
				return (java.sql.Date) paramValue;
			}
			if (paramValue instanceof java.util.Date) {
				return new java.sql.Date(((java.util.Date) paramValue).getTime());
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return new java.sql.Date(oracleDateConvert(paramValue).getTime());
			}
			if (isBlank) {
				return null;
			}
			return new java.sql.Date(DateUtil.parseString(valueStr).getTime());
		}
		// 27 clob 类型比较特殊,对外转类型全部转为字符串
		if (DataType.clobType == typeValue) {
			// update 2020-6-23 增加兼容性判断
			if (paramValue instanceof String) {
				return valueStr;
			}
			java.sql.Clob clob = (java.sql.Clob) paramValue;
			BufferedReader in = new BufferedReader(clob.getCharacterStream());
			StringWriter out = new StringWriter();
			int c;
			while ((c = in.read()) != -1) {
				out.write(c);
			}
			return out.toString();
		}
		// 28
		if (DataType.sqlTimeType == typeValue) {
			if (paramValue instanceof java.sql.Time) {
				return (java.sql.Time) paramValue;
			}
			if (paramValue instanceof java.util.Date) {
				return new java.sql.Time(((java.util.Date) paramValue).getTime());
			}
			if ("oracle.sql.TIMESTAMP".equals(paramValue.getClass().getTypeName())) {
				return new java.sql.Time(oracleDateConvert(paramValue).getTime());
			}
			return new java.sql.Time(DateUtil.parseString(valueStr).getTime());
		}
		// 29
		if (DataType.primitiveByteType == typeValue) {
			return Byte.valueOf(valueStr).byteValue();
		}
		// 30
		if (DataType.primitiveCharType == typeValue) {
			if (isBlank) {
				return " ".charAt(0);
			}
			return valueStr.charAt(0);
		}
		// 31 字符数组
		if (DataType.aryCharType == typeValue) {
			if (paramValue instanceof char[]) {
				return (char[]) paramValue;
			}
			if (paramValue instanceof java.sql.Clob) {
				java.sql.Clob clob = (java.sql.Clob) paramValue;
				BufferedReader in = new BufferedReader(clob.getCharacterStream());
				StringWriter out = new StringWriter();
				int c;
				while ((c = in.read()) != -1) {
					out.write(c);
				}
				return out.toString().toCharArray();
			}
			return valueStr.toCharArray();
		}
		// 32 update by 2020-4-13增加Byte类型的处理
		if (DataType.wrapByteType == typeValue) {
			return Byte.valueOf(valueStr);
		}
		// 33 数组类型
		if (typeValue == DataType.aryOtherType && (paramValue instanceof Array)) {
			return convertArray(((Array) paramValue).getArray(), typeName);
		}
		return paramValue;
	}

	public static String convertBoolean(String var) {
		if ("true".equals(var)) {
			return "1";
		}
		if ("false".equals(var)) {
			return "0";
		}
		return var;
	}

	private static Timestamp oracleTimeStampConvert(Object obj) throws Exception {
		return ((oracle.sql.TIMESTAMP) obj).timestampValue();
	}

	private static Date oracleDateConvert(Object obj) throws Exception {
		return ((oracle.sql.TIMESTAMP) obj).dateValue();
	}

	/**
	 * @todo 利用java.lang.reflect并结合页面的property， 从对象中取出对应方法的值，组成一个List
	 * @param datas
	 * @param props
	 * @return
	 */
	public static List reflectBeansToList(List datas, String[] props) throws RuntimeException {
		return reflectBeansToList(datas, props, null);
	}

	/**
	 * @TODO 切取单列值并以数组返回,服务于loadAll方法
	 * @param datas
	 * @param propertyName
	 * @return
	 * @throws Exception
	 */
	public static Object[] sliceToArray(List datas, String propertyName) throws RuntimeException {
		List sliceList = reflectBeansToList(datas, new String[] { propertyName }, null);
		if (sliceList == null || sliceList.isEmpty()) {
			return null;
		}
		List result = new ArrayList();
		List row;
		for (int i = 0; i < sliceList.size(); i++) {
			row = (List) sliceList.get(i);
			if (row != null && row.get(0) != null) {
				result.add(row.get(0));
			}
		}
		if (result.isEmpty()) {
			return null;
		}
		Object[] ary = new Object[result.size()];
		result.toArray(ary);
		return ary;
	}

	/**
	 * @todo 利用java.lang.reflect并结合页面的property， 从对象中取出对应方法的值，组成一个List
	 * @param datas
	 * @param properties
	 * @param reflectPropsHandler
	 * @return
	 * @throws Exception
	 */
	public static List reflectBeansToList(List datas, String[] properties, ReflectPropsHandler reflectPropsHandler)
			throws RuntimeException {
		if (null == datas || datas.isEmpty() || null == properties || properties.length < 1) {
			return null;
		}
		List resultList = new ArrayList();
		try {
			Object rowObject = null;
			int methodLength = properties.length;
			// 判断是否存在属性值处理反调
			boolean hasHandler = (reflectPropsHandler != null) ? true : false;
			// 存在反调，则将对象的属性和属性所在的顺序放入hashMap中，便于后面反调中通过属性调用
			if (hasHandler) {
				HashMap<String, Integer> propertyIndexMap = new HashMap<String, Integer>();
				for (int i = 0; i < methodLength; i++) {
					propertyIndexMap.put(properties[i].toLowerCase(), i);
				}
				reflectPropsHandler.setPropertyIndexMap(propertyIndexMap);
			}

			// 判断是否有级联
			boolean hasInnerClass = false;
			for (String prop : properties) {
				if (prop.contains(".")) {
					hasInnerClass = true;
					break;
				}
			}
			// 级联含子对象模式(属性名称:staff.name 模式)
			if (hasInnerClass) {
				Object[] rowAry;
				for (int i = 0, n = datas.size(); i < n; i++) {
					rowObject = datas.get(i);
					if (rowObject != null) {
						List rowList = new ArrayList();
						rowAry = reflectBeanToAry(rowObject, properties, null, reflectPropsHandler);
						for (Object cell : rowAry) {
							rowList.add(cell);
						}
						resultList.add(rowList);
					}
				}
				return resultList;
			}

			// 非级联模式
			Method[] realMethods = null;
			boolean inited = false;
			Object[] params = new Object[] {};
			// 增加map类型支持
			boolean isMap = false;
			if (datas.get(0) != null && Map.class.isAssignableFrom(datas.get(0).getClass())) {
				isMap = true;
			}
			Iterator iter;
			String fieldLow;
			Map.Entry<String, Object> entry;
			Map rowMap;
			for (int i = 0, n = datas.size(); i < n; i++) {
				rowObject = datas.get(i);
				if (null != rowObject) {
					List dataList = new ArrayList();
					// 2021-10-09 支持map类型
					if (isMap) {
						if (rowObject instanceof IgnoreKeyCaseMap) {
							rowMap = (IgnoreKeyCaseMap) rowObject;
							for (int j = 0; j < methodLength; j++) {
								dataList.add(rowMap.get(properties[j]));
							}
						} else {
							rowMap = (Map) rowObject;
							// 考虑key大小写兼容
							for (int j = 0; j < methodLength; j++) {
								fieldLow = properties[j].toLowerCase();
								iter = rowMap.entrySet().iterator();
								while (iter.hasNext()) {
									entry = (Map.Entry<String, Object>) iter.next();
									if (entry.getKey().toLowerCase().equals(fieldLow)) {
										dataList.add(entry.getValue());
										break;
									}
								}
							}
						}
					} else {
						// 第一行数据
						if (!inited) {
							realMethods = matchGetMethods(rowObject.getClass(), properties);
							inited = true;
						}
						for (int j = 0; j < methodLength; j++) {
							if (realMethods[j] != null) {
								dataList.add(realMethods[j].invoke(rowObject, params));
							} else {
								dataList.add(null);
							}
						}
					}
					// 反调对数据值进行加工处理
					if (hasHandler) {
						reflectPropsHandler.setRowIndex(i);
						reflectPropsHandler.setRowList(dataList);
						reflectPropsHandler.process();
						resultList.add(reflectPropsHandler.getRowList());
					} else {
						resultList.add(dataList);
					}
				} else {
					if (logger.isDebugEnabled()) {
						logger.debug("BeanUtil.reflectBeansToList 方法,第:{}行数据为null,如果是sql查询请检查写法是否正确!", i);
					} else {
						err.println("BeanUtil.reflectBeansToList 方法,第:{" + i + "}行数据为null,如果是sql查询请检查写法是否正确!");
					}
					resultList.add(null);
				}
			}
		} catch (Exception e) {
			logger.error("反射Java Bean获取数据组装List集合异常!{}", e.getMessage());
			e.printStackTrace();
			throw new RuntimeException("反射Java Bean获取数据组装List集合异常!" + e.getMessage());
		}
		return resultList;
	}

	public static Object[] reflectBeanToAry(Object serializable, String[] properties) {
		return reflectBeanToAry(serializable, properties, null, null);
	}

	/**
	 * @todo 反射出单个对象中的属性并以对象数组返回
	 * @param serializable
	 * @param properties
	 * @param defaultValues
	 * @param reflectPropsHandler
	 * @return
	 */
	public static Object[] reflectBeanToAry(Object serializable, String[] properties, Object[] defaultValues,
			ReflectPropsHandler reflectPropsHandler) {
		if (null == serializable || null == properties || properties.length == 0) {
			return null;
		}
		int methodLength = properties.length;
		Object[] result = new Object[methodLength];
		// 判断是否存在属性值处理反调
		boolean hasHandler = (reflectPropsHandler != null) ? true : false;
		// 存在反调，则将对象的属性和属性所在的顺序放入hashMap中，便于后面反调中通过属性调用
		if (hasHandler && !reflectPropsHandler.initPropsIndexMap()) {
			HashMap<String, Integer> propertyIndexMap = new HashMap<String, Integer>();
			for (int i = 0; i < methodLength; i++) {
				propertyIndexMap.put(properties[i].toLowerCase(), i);
			}
			reflectPropsHandler.setPropertyIndexMap(propertyIndexMap);
		}
		String[] fields;
		Iterator<?> iter;
		Map.Entry<String, Object> entry;
		boolean isMapped = false;
		String fieldTrim;
		String fieldLow;
		Object fieldValue;
		boolean hasKey = false;
		try {
			KeyAndIndex keyAndIndex;
			// 通过反射提取属性getMethod返回的数据值
			for (int i = 0; i < methodLength; i++) {
				if (properties[i] != null) {
					// 支持xxxx.xxx 子对象属性提取
					fields = properties[i].split("\\.");
					fieldValue = serializable;
					hasKey = false;
					// map 类型且key本身就是xxxx.xxxx格式
					if (fieldValue instanceof Map) {
						iter = ((Map) fieldValue).entrySet().iterator();
						fieldLow = properties[i].trim().toLowerCase();
						while (iter.hasNext()) {
							entry = (Map.Entry<String, Object>) iter.next();
							if (entry.getKey().toLowerCase().equals(fieldLow)) {
								fieldValue = entry.getValue();
								hasKey = true;
								break;
							}
						}
					}
					if (!hasKey) {
						int index = 0;
						int fieldLen = fields.length;
						for (String field : fields) {
							fieldTrim = field.trim();
							// 支持map类型 update 2021-01-31
							if (fieldValue instanceof Map) {
								if (fieldValue instanceof IgnoreKeyCaseMap) {
									if (!((IgnoreKeyCaseMap) fieldValue).containsKey(fieldTrim)) {
										keyAndIndex = getKeyAndIndex(fieldTrim);
										if (keyAndIndex != null) {
											fieldValue = getAryPropValue(
													((IgnoreKeyCaseMap) fieldValue).get(keyAndIndex.getKey()),
													keyAndIndex.getIndex());
										} else {
											fieldValue = null;
										}
									} else {
										fieldValue = ((IgnoreKeyCaseMap) fieldValue).get(fieldTrim);
									}
								} else {
									iter = ((Map) fieldValue).entrySet().iterator();
									isMapped = false;
									fieldLow = fieldTrim.toLowerCase();
									while (iter.hasNext()) {
										entry = (Map.Entry<String, Object>) iter.next();
										if (entry.getKey().toLowerCase().equals(fieldLow)) {
											fieldValue = entry.getValue();
											isMapped = true;
											break;
										} else {
											keyAndIndex = getKeyAndIndex(fieldLow);
											if (keyAndIndex != null
													&& entry.getKey().toLowerCase().equals(keyAndIndex.getKey())) {
												fieldValue = getAryPropValue(entry.getValue(), keyAndIndex.getIndex());
												isMapped = true;
												break;
											}
										}
									}
									if (!isMapped) {
										fieldValue = null;
									}
								}
							} // update 2022-5-25 支持将集合的属性直接映射成数组
							else if (fieldValue instanceof List) {
								List tmp = (List) fieldValue;
								// a.b.c 在最后一个属性c之前的属性取值
								if (index < fieldLen - 1) {
									fieldValue = sliceToArray(tmp, fieldTrim);
								} else {
									Object[] fieldValueAry = new Object[tmp.size()];
									for (int j = 0; j < tmp.size(); j++) {
										fieldValueAry[j] = getComplexProperty(tmp.get(j), fieldTrim);
									}
									fieldValue = fieldValueAry;
								}
							} else if (fieldValue instanceof Object[]) {
								Object[] tmp = (Object[]) fieldValue;
								Object[] fieldValueAry = new Object[tmp.length];
								for (int j = 0; j < tmp.length; j++) {
									fieldValueAry[j] = getComplexProperty(tmp[j], fieldTrim);
								}
								fieldValue = fieldValueAry;
							} else {
								fieldValue = getComplexProperty(fieldValue, fieldTrim);
							}
							if (fieldValue == null) {
								break;
							}
							index++;
						}
					}
					result[i] = fieldValue;
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		// 默认值
		if (defaultValues != null) {
			int end = (defaultValues.length > methodLength) ? methodLength : defaultValues.length;
			for (int i = 0; i < end; i++) {
				if (result[i] == null) {
					result[i] = defaultValues[i];
				}
			}
		}
		// 反调对数据值进行加工处理
		if (hasHandler) {
			reflectPropsHandler.setRowIndex(0);
			reflectPropsHandler.setRowData(result);
			reflectPropsHandler.process();
			return reflectPropsHandler.getRowData();
		}
		return result;
	}

	/**
	 * @todo 利用java.lang.reflect并结合页面的property， 从对象中取出对应方法的值，组成一个List
	 * @param dataSet
	 * @param properties
	 * @param defaultValues
	 * @param reflectPropsHandler
	 * @return
	 */
	public static List<Object[]> reflectBeansToInnerAry(List dataSet, String[] properties, Object[] defaultValues,
			ReflectPropsHandler reflectPropsHandler) {
		if (null == dataSet || dataSet.isEmpty() || null == properties || properties.length < 1) {
			return null;
		}
		List<Object[]> resultList = new ArrayList<Object[]>();
		try {
			int methodLength = properties.length;
			int defaultValueLength = (defaultValues == null) ? 0 : defaultValues.length;
			Method[] realMethods = null;
			boolean inited = false;
			Object rowObject = null;
			Object[] params = new Object[] {};
			// 判断是否存在属性值处理反调
			boolean hasHandler = (reflectPropsHandler != null) ? true : false;
			// 存在反调，则将对象的属性和属性所在的顺序放入hashMap中，便于后面反调中通过属性调用
			if (hasHandler) {
				HashMap<String, Integer> propertyIndexMap = new HashMap<String, Integer>();
				for (int i = 0; i < methodLength; i++) {
					propertyIndexMap.put(properties[i].toLowerCase(), i);
				}
				reflectPropsHandler.setPropertyIndexMap(propertyIndexMap);
			}
			// 逐行提取属性数据
			for (int i = 0, n = dataSet.size(); i < n; i++) {
				rowObject = dataSet.get(i);
				if (null != rowObject) {
					// 初始化属性对应getMethod的位置,提升反射的效率
					if (!inited) {
						realMethods = matchGetMethods(rowObject.getClass(), properties);
						inited = true;
					}
					Object[] dataAry = new Object[methodLength];
					// 通过反射提取属性getMethod返回的数据值
					for (int j = 0; j < methodLength; j++) {
						if (null != realMethods[j]) {
							dataAry[j] = realMethods[j].invoke(rowObject, params);
							if (null == dataAry[j] && null != defaultValues) {
								dataAry[j] = (j >= defaultValueLength) ? null : defaultValues[j];
							}
						} else {
							if (null == defaultValues) {
								dataAry[j] = null;
							} else {
								dataAry[j] = (j >= defaultValueLength) ? null : defaultValues[j];
							}
						}
					}
					// 反调对数据值进行加工处理
					if (hasHandler) {
						reflectPropsHandler.setRowIndex(i);
						reflectPropsHandler.setRowData(dataAry);
						reflectPropsHandler.process();
						resultList.add(reflectPropsHandler.getRowData());
					} else {
						resultList.add(dataAry);
					}
				} else {
					if (logger.isDebugEnabled()) {
						logger.debug("BeanUtil.reflectBeansToInnerAry 方法,第:{}行数据为null,如果是sql查询请检查写法是否正确!", i);
					} else {
						err.println("BeanUtil.reflectBeansToInnerAry 方法,第:{" + i + "}行数据为null,如果是sql查询请检查写法是否正确!");
					}
					resultList.add(null);
				}
			}
		} catch (Exception e) {
			logger.error("反射Java Bean获取数据组装List集合异常!{}", e.getMessage());
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return resultList;
	}

	public static List reflectListToBean(TypeHandler typeHandler, Collection datas, String[] properties,
			Class voClass) {
		int[] indexs = null;
		if (properties != null && properties.length > 0) {
			indexs = new int[properties.length];
			for (int i = 0; i < indexs.length; i++) {
				indexs[i] = i;
			}
		}
		return reflectListToBean(typeHandler, datas, indexs, properties, voClass, true);
	}

	/**
	 * @todo 将二维数组映射到对象集合中
	 * @param typeHandler
	 * @param datas
	 * @param indexs
	 * @param properties
	 * @param voClass
	 * @return
	 * @throws RuntimeException
	 */
	public static List reflectListToBean(TypeHandler typeHandler, Collection datas, int[] indexs, String[] properties,
			Class voClass) throws RuntimeException {
		return reflectListToBean(typeHandler, datas, indexs, properties, voClass, true);
	}

	/**
	 * @todo 利用java.lang.reflect并结合页面的property， 从对象中取出对应方法的值，组成一个List
	 * @param typeHandler
	 * @param datas
	 * @param indexs
	 * @param properties
	 * @param voClass
	 * @param autoConvertType
	 * @return
	 */
	public static List reflectListToBean(TypeHandler typeHandler, Collection datas, int[] indexs, String[] properties,
			Class voClass, boolean autoConvertType) {
		if (null == datas || datas.isEmpty()) {
			return null;
		}
		if (null == properties || properties.length < 1 || null == voClass || null == indexs || indexs.length == 0
				|| properties.length != indexs.length) {
			throw new IllegalArgumentException("集合或属性名称数组为空,请检查参数信息!");
		}
		if (Modifier.isAbstract(voClass.getModifiers()) || Modifier.isInterface(voClass.getModifiers())) {
			throw new IllegalArgumentException("toClassType:" + voClass.getName() + " 是抽象类或接口,非法参数!");
		}
		List resultList = new ArrayList();
		Object cellData = null;
		String propertyName = null;
		try {
			Object rowObject = null;
			Object bean;
			boolean isArray = false;
			int meter = 0;
			Object[] rowArray;
			List rowList;
			int indexSize = indexs.length;
			Method[] realMethods = matchSetMethods(voClass, properties);
			String[] methodTypes = new String[indexSize];
			int[] methodTypeValues = new int[indexSize];
			Class[] genericTypes = new Class[indexSize];
			Type[] types;
			// 自动适配属性的数据类型
			if (autoConvertType) {
				for (int i = 0; i < indexSize; i++) {
					if (null != realMethods[i]) {
						methodTypes[i] = realMethods[i].getParameterTypes()[0].getTypeName();
						methodTypeValues[i] = DataType.getType(methodTypes[i]);
						types = realMethods[i].getGenericParameterTypes();
						if (types.length > 0) {
							if (types[0] instanceof ParameterizedType) {
								genericTypes[i] = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0];
							}
						}
					}
				}
			}

			Iterator iter = datas.iterator();
			int index = 0;
			int size;
			while (iter.hasNext()) {
				rowObject = iter.next();
				if (rowObject != null) {
					bean = voClass.getDeclaredConstructor().newInstance();
					if (meter == 0) {
						if (rowObject instanceof Object[]) {
							isArray = true;
						}
					}
					if (isArray) {
						rowArray = (Object[]) rowObject;
						size = rowArray.length;
						for (int i = 0; i < indexSize; i++) {
							if (indexs[i] < size) {
								cellData = rowArray[indexs[i]];
								if (realMethods[i] != null && cellData != null) {
									propertyName = realMethods[i].getName();
									// 类型相同
									if (cellData.getClass().getTypeName().equals(methodTypes[i])) {
										realMethods[i].invoke(bean, cellData);
									} else {
										realMethods[i].invoke(bean,
												autoConvertType
														? convertType(typeHandler, cellData, methodTypeValues[i],
																methodTypes[i], genericTypes[i])
														: cellData);
									}
								}
							}
						}
					} else {
						rowList = (List) rowObject;
						size = rowList.size();
						for (int i = 0; i < indexSize; i++) {
							if (indexs[i] < size) {
								cellData = rowList.get(indexs[i]);
								if (realMethods[i] != null && cellData != null) {
									propertyName = realMethods[i].getName();
									if (cellData.getClass().getTypeName().equals(methodTypes[i])) {
										realMethods[i].invoke(bean, cellData);
									} else {
										realMethods[i].invoke(bean,
												autoConvertType
														? convertType(typeHandler, cellData, methodTypeValues[i],
																methodTypes[i], genericTypes[i])
														: cellData);
									}
								}
							}
						}
					}
					resultList.add(bean);
					meter++;
				} else {
					if (logger.isDebugEnabled()) {
						logger.debug("BeanUtil.reflectListToBean 方法,第:{}行数据为null,如果是sql查询请检查写法是否正确!", index);
					} else {
						err.println("BeanUtil.reflectListToBean 方法,第:{" + index + "}行数据为null,如果是sql查询请检查写法是否正确!");
					}
					resultList.add(null);
				}
				index++;
			}
		} catch (Exception e) {
			if (propertyName == null) {
				logger.error("将集合数据映射到类:{} 异常,请检查类是否正确!{}", voClass.getName(), e.getMessage());
			} else {
				logger.error("将集合数据:{} 映射到类:{} 的属性:{}过程异常!{}", cellData, voClass.getName(), propertyName,
						e.getMessage());
			}
			throw new RuntimeException(e);
		}
		return resultList;
	}

	public static <T extends Serializable> T reflectRowToBean(TypeHandler typeHandler, Method[] realMethods,
			int[] methodTypeValues, String[] methodTypes, Class[] genericTypes, List rowList, int[] indexs,
			String[] properties, Class<T> voClass) {
		Object cellData = null;
		String propertyName = null;
		Object bean = null;
		try {
			bean = voClass.getDeclaredConstructor().newInstance();
			int indexSize = indexs.length;
			int size = rowList.size();
			for (int i = 0; i < indexSize; i++) {
				if (indexs[i] < size) {
					cellData = rowList.get(indexs[i]);
					if (realMethods[i] != null && cellData != null) {
						propertyName = realMethods[i].getName();
						if (cellData.getClass().getTypeName().equals(methodTypes[i])) {
							realMethods[i].invoke(bean, cellData);
						} else {
							realMethods[i].invoke(bean, convertType(typeHandler, cellData, methodTypeValues[i],
									methodTypes[i], genericTypes[i]));
						}
					}
				}
			}
		} catch (Exception e) {
			if (propertyName == null) {
				logger.error("将集合数据映射到类:{} 异常,请检查类是否正确!{}", voClass.getName(), e.getMessage());
			} else {
				logger.error("将集合数据:{} 映射到类:{} 的属性:{}过程异常!{}", cellData, voClass.getName(), propertyName,
						e.getMessage());
			}
			throw new RuntimeException(e);
		}
		return (T) bean;
	}

	public static void batchSetProperties(Collection voList, String[] properties, Object[] values,
			boolean autoConvertType) {
		batchSetProperties(voList, properties, values, autoConvertType, true);
	}

	/**
	 * @todo 批量对集合的属性设置相同的值
	 * @param voList
	 * @param properties
	 * @param values
	 * @param autoConvertType
	 * @param forceUpdate
	 */
	public static void batchSetProperties(Collection voList, String[] properties, Object[] values,
			boolean autoConvertType, boolean forceUpdate) {
		if (null == voList || voList.isEmpty()) {
			return;
		}
		if (null == properties || properties.length < 1 || null == values || values.length < 1
				|| properties.length != values.length) {
			throw new IllegalArgumentException("集合或属性名称数组为空,请检查参数信息!");
		}
		try {
			int indexSize = properties.length;
			Method[] realMethods = null;
			String[] methodTypes = new String[indexSize];
			int[] methodTypeValues = new int[indexSize];
			Class[] genericTypes = new Class[indexSize];
			Type[] types;
			Iterator iter = voList.iterator();
			Object bean;
			boolean inited = false;
			while (iter.hasNext()) {
				bean = iter.next();
				if (null != bean) {
					if (!inited) {
						realMethods = matchSetMethods(bean.getClass(), properties);
						if (autoConvertType) {
							for (int i = 0; i < indexSize; i++) {
								if (realMethods[i] != null) {
									methodTypes[i] = realMethods[i].getParameterTypes()[0].getTypeName();
									methodTypeValues[i] = DataType.getType(methodTypes[i]);
									types = realMethods[i].getGenericParameterTypes();
									if (types.length > 0) {
										if (types[0] instanceof ParameterizedType) {
											genericTypes[i] = (Class) ((ParameterizedType) types[0])
													.getActualTypeArguments()[0];
										}
									}
								}
							}
						}
						inited = true;
					}
					for (int i = 0; i < indexSize; i++) {
						if (realMethods[i] != null && (forceUpdate || values[i] != null)) {
							realMethods[i].invoke(bean,
									autoConvertType
											? convertType(null, values[i], methodTypeValues[i], methodTypes[i],
													genericTypes[i])
											: values[i]);
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("将集合数据反射到Java Bean过程异常!{}", e.getMessage());
			e.printStackTrace();
			throw new RuntimeException("将集合数据反射到Java Bean过程异常!{}" + e.getMessage(), e);
		}
	}

	/**
	 * @todo 对集合属性进行赋值
	 * @param voList
	 * @param properties
	 * @param values
	 * @param index
	 * @param autoConvertType
	 * @throws RuntimeException
	 */
	public static void mappingSetProperties(Collection voList, String[] properties, List<Object[]> values, int[] index,
			boolean autoConvertType) throws RuntimeException {
		mappingSetProperties(voList, properties, values, index, autoConvertType, true);
	}

	public static void mappingSetProperties(Collection voList, String[] properties, List<Object[]> values, int[] index,
			boolean autoConvertType, boolean forceUpdate) throws RuntimeException {
		if (null == voList || voList.isEmpty()) {
			return;
		}
		if (null == properties || properties.length < 1 || null == values || values.get(0).length < 1
				|| properties.length != index.length) {
			throw new IllegalArgumentException("集合或属性名称数组为空,请检查参数信息!");
		}
		try {
			int indexSize = properties.length;
			Method[] realMethods = null;
			String[] methodTypes = new String[indexSize];
			int[] methodTypeValues = new int[indexSize];
			Class[] genericTypes = new Class[indexSize];
			Type[] types;
			Iterator iter = voList.iterator();
			Object bean;
			boolean inited = false;
			int rowIndex = 0;
			Object[] rowData;
			while (iter.hasNext()) {
				if (rowIndex > values.size() - 1) {
					break;
				}
				rowData = values.get(rowIndex);
				bean = iter.next();
				if (null != bean) {
					if (!inited) {
						realMethods = matchSetMethods(bean.getClass(), properties);
						if (autoConvertType) {
							for (int i = 0; i < indexSize; i++) {
								if (realMethods[i] != null) {
									methodTypes[i] = realMethods[i].getParameterTypes()[0].getTypeName();
									methodTypeValues[i] = DataType.getType(methodTypes[i]);
									types = realMethods[i].getGenericParameterTypes();
									if (types.length > 0) {
										if (types[0] instanceof ParameterizedType) {
											genericTypes[i] = (Class) ((ParameterizedType) types[0])
													.getActualTypeArguments()[0];
										}
									}
								}
							}
						}
						inited = true;
					}
					for (int i = 0; i < indexSize; i++) {
						if (realMethods[i] != null && (forceUpdate || rowData[index[i]] != null)) {
							realMethods[i].invoke(bean,
									autoConvertType
											? convertType(null, rowData[index[i]], methodTypeValues[i], methodTypes[i],
													genericTypes[i])
											: rowData[index[i]]);
						}
					}
				}
				rowIndex++;
			}
		} catch (Exception e) {
			logger.error("将集合数据反射到Java Bean过程异常!{}", e.getMessage());
			e.printStackTrace();
			throw new RuntimeException("将集合数据反射到Java Bean过程异常!" + e.getMessage());
		}
	}

	public static String[] matchSetMethodNames(Class voClass) {
		return matchMethodNames(voClass, false);
	}

	private static String[] matchMethodNames(Class voClass, boolean isGet) {
		Method[] methods = voClass.getMethods();
		int methodCnt = methods.length;
		List<String> methodAry = new ArrayList();
		String methodName;
		Method method;
		for (int i = 0; i < methodCnt; i++) {
			method = methods[i];
			methodName = method.getName();
			if (isGet) {
				if ((methodName.startsWith("get") || methodName.startsWith("is"))
						&& !void.class.equals(method.getReturnType()) && method.getParameterTypes().length == 0
						&& !"getclass".equals(methodName.toLowerCase())) {
					methodAry.add(StringUtil.firstToLowerCase(methodName.replaceFirst("get|is", "")));
				}
			} else {
				if (methodName.startsWith("set") && void.class.equals(method.getReturnType())
						&& method.getParameterTypes().length == 1) {
					methodAry.add(StringUtil.firstToLowerCase(methodName.replaceFirst("set", "")));
				}
			}
		}
		String[] result = new String[methodAry.size()];
		methodAry.toArray(result);
		return result;
	}

	/**
	 * @todo 根据方法名称以及参数数量获取类的具体方法
	 * @param beanClass
	 * @param methodName
	 * @param argLength
	 * @return
	 */
	public static Method getMethod(Class beanClass, String methodName, int argLength) {
		Method[] methods = beanClass.getMethods();
		int methodArgsLength;
		for (Method method : methods) {
			methodArgsLength = 0;
			if (method.getParameterTypes() != null) {
				methodArgsLength = method.getParameterTypes().length;
			}
			if (method.getName().equalsIgnoreCase(methodName) && methodArgsLength == argLength) {
				return method;
			}
		}
		return null;
	}

	/**
	 * @todo 判断对象是否是基本数据类型对象
	 * @param clazz
	 * @return
	 */
	public static boolean isBaseDataType(Class clazz) {
		return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)
				|| clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
				|| clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
				|| clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
				|| clazz.equals(LocalDate.class) || clazz.equals(LocalDateTime.class) || clazz.equals(LocalTime.class)
				|| clazz.equals(Timestamp.class) || clazz.isPrimitive());
	}

	/**
	 * @TODO 代替PropertyUtil 和BeanUtils的setProperty方法
	 * @param bean
	 * @param property
	 * @param value
	 * @throws RuntimeException
	 */
	public static void setProperty(Object bean, String property, Object value) throws RuntimeException {
		String key = bean.getClass().getName().concat(":set").concat(property);
		// 利用缓存提升方法匹配效率
		Method method = setMethods.get(key);
		if (method == null) {
			method = matchSetMethods(bean.getClass(), new String[] { property })[0];
			if (method == null) {
				throw new RuntimeException(bean.getClass().getName() + " 没有对应的:" + property);
			}
			setMethods.put(key, method);
		}
		// 将数据类型进行转换再赋值
		String typeName = method.getParameterTypes()[0].getTypeName();
		Type[] types = method.getGenericParameterTypes();
		Class genericType = null;
		if (types.length > 0) {
			if (types[0] instanceof ParameterizedType) {
				genericType = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0];
			}
		}
		try {
			method.invoke(bean, convertType(null, value, DataType.getType(typeName), typeName, genericType));
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * @TODO 代替BeanUtils.getProperty 方法
	 * @param bean
	 * @param property
	 * @return
	 * @throws RuntimeException
	 */
	public static Object getProperty(Object bean, String property) throws RuntimeException {
		if (bean instanceof Map) {
			return ((Map) bean).get(property);
		}
		String key = bean.getClass().getName().concat(":get").concat(property);
		// 利用缓存提升方法匹配效率
		Method method = getMethods.get(key);
		if (method == null) {
			method = matchGetMethods(bean.getClass(), new String[] { property })[0];
			if (method == null) {
				return null;
			}
			getMethods.put(key, method);
		}
		Object result = null;
		try {
			result = method.invoke(bean);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}
		return result;
	}

	/**
	 * @TODO 代替BeanUtils.getProperty 方法,增加item[1] 数组模式调用
	 * @param bean
	 * @param property
	 * @return
	 * @throws RuntimeException
	 */
	public static Object getComplexProperty(Object bean, String property) throws RuntimeException {
		KeyAndIndex keyAndIndex = getKeyAndIndex(property);
		String realProperty = (keyAndIndex == null) ? property : keyAndIndex.getKey();
		Object result = null;
		if (bean instanceof Map) {
			result = ((Map) bean).get(property);
			if (result == null && keyAndIndex != null) {
				result = getAryPropValue(((Map) bean).get(realProperty), keyAndIndex.getIndex());
			}
			return result;
		}
		String key = bean.getClass().getName().concat(":get").concat(realProperty);
		// 利用缓存提升方法匹配效率
		Method method = getMethods.get(key);
		if (method == null) {
			method = matchGetMethods(bean.getClass(), new String[] { realProperty })[0];
			if (method == null) {
				return null;
			}
			getMethods.put(key, method);
		}
		try {
			result = method.invoke(bean);
			if (result != null && keyAndIndex != null) {
				result = getAryPropValue(result, keyAndIndex.getIndex());
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}
		return result;
	}

	/**
	 * @TODO 为loadByIds提供Entity集合封装,便于将调用方式统一
	 * @param <T>
	 * @param typeHandler
	 * @param entityMeta
	 * @param voClass
	 * @param ids
	 * @return
	 */
	public static <T extends Serializable> List<T> wrapEntities(TypeHandler typeHandler, EntityMeta entityMeta,
			Class<T> voClass, Object... ids) {
		List<T> entities = new ArrayList<T>();
		Set<Object> repeat = new HashSet<Object>();
		try {
			// 获取主键的set方法
			Method method = BeanUtil.matchSetMethods(voClass, entityMeta.getIdArray())[0];
			String typeName = method.getParameterTypes()[0].getTypeName();
			int typeValue = DataType.getType(typeName);
			Type[] types = method.getGenericParameterTypes();
			Class genericType = null;
			if (types.length > 0) {
				if (types[0] instanceof ParameterizedType) {
					genericType = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0];
				}
			}
			T bean;
			for (Object id : ids) {
				// 去除重复
				if (id != null && !repeat.contains(id)) {
					bean = voClass.getDeclaredConstructor().newInstance();
					method.invoke(bean, convertType(typeHandler, id, typeValue, typeName, genericType));
					entities.add(bean);
					repeat.add(id);
				}
			}
		} catch (Exception e) {
			logger.error("将集合数据反射到Java Bean过程异常!{}", e.getMessage());
			throw new RuntimeException(e);
		}
		return entities;
	}

	/**
	 * @TODO 获取VO对应的实际的entityClass,主要是规避{{}}实例导致无法正确获取类型
	 * @param entityClass
	 * @return
	 */
	public static Class getEntityClass(Class entityClass) {
		// update 2020-9-16
		// 主要规避VO对象{{}}模式初始化，导致Class获取变成了内部类(双括号实例化modifiers会等于0)
		// {{}}实例化得到的class是不正确的，所以这里将==0的进入后续判断
		if (entityClass == null || entityClass.equals(Object.class) || entityClass.getModifiers() != 0) {
			return entityClass;
		}
		Class realEntityClass = entityClass;
		// 通过逐层递归来判断是否SqlToy annotation注解所规定的关联数据库的实体类
		// 即@Entity 注解的抽象类
		while (!realEntityClass.equals(Object.class)) {
			// 实体bean
			if (realEntityClass.isAnnotationPresent(SqlToyEntity.class)
					|| (realEntityClass.isAnnotationPresent(Entity.class)
							&& !Modifier.isAbstract(realEntityClass.getModifiers()))) {
				return realEntityClass;
			}
			realEntityClass = realEntityClass.getSuperclass();
		}
		if (entityClass.getModifiers() == 0 && !entityClass.getSuperclass().equals(Object.class)) {
			return entityClass.getSuperclass();
		}
		return entityClass;
	}

	/**
	 * @TODO 对常规类型进行转换，超出部分由自定义类型处理器完成(或配置类型完全一致)
	 * @param values
	 * @param typeName
	 * @return
	 */
	public static Object convertArray(Object values, String typeName) {
		// 类型完全一致
		if (typeName.equals(values.getClass().getTypeName())) {
			return values;
		}
		Object[] array = (Object[]) values;
		int index = 0;
		if (typeName.equals("java.lang.Integer[]") && !(values instanceof Integer[])) {
			Integer[] result = new Integer[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Integer.valueOf(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("java.lang.Long[]") && !(values instanceof Long[])) {
			Long[] result = new Long[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Long.valueOf(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("java.math.BigDecimal[]") && !(values instanceof BigDecimal[])) {
			BigDecimal[] result = new BigDecimal[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = new BigDecimal(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("int[]") && !(values instanceof int[])) {
			int[] result = new int[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Integer.parseInt(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("long[]") && !(values instanceof long[])) {
			long[] result = new long[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Long.parseLong(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("java.lang.Double[]") && !(values instanceof Double[])) {
			Double[] result = new Double[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Double.valueOf(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("double[]") && !(values instanceof double[])) {
			double[] result = new double[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Double.parseDouble(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("java.lang.Float[]") && !(values instanceof Float[])) {
			Float[] result = new Float[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Float.valueOf(obj.toString());
				}
				index++;
			}
			return result;
		}
		if (typeName.equals("float[]") && !(values instanceof float[])) {
			float[] result = new float[array.length];
			for (Object obj : array) {
				if (obj != null) {
					result[index] = Float.parseFloat(obj.toString());
				}
				index++;
			}
			return result;
		}
		return values;
	}

	/**
	 * @TODO 针对loadAll级联加载场景,子表通过主表id集合批量一次性完成加载的，所以子表集合包含了主表集合的全部关联信息
	 * @param mainEntities
	 * @param itemEntities
	 * @param cascadeModel
	 * @throws Exception
	 */
	public static void loadAllMapping(List mainEntities, List itemEntities, TableCascadeModel cascadeModel)
			throws Exception {
		if (mainEntities == null || mainEntities.isEmpty() || itemEntities == null || itemEntities.isEmpty()) {
			return;
		}
		boolean isOneToMany = (cascadeModel.getCascadeType() == 1);
		Object mainEntity;
		String[] mainProps = cascadeModel.getFields();
		Object[] mainValues;
		Object[] mappedFieldValues;
		String property = cascadeModel.getProperty();
		Object itemEntity;
		String[] mappedFields = cascadeModel.getMappedFields();
		List itemList = null;
		int fieldLength = mainProps.length;
		boolean isEqual = true;
		int itemSize = 0;
		for (int i = 0; i < mainEntities.size(); i++) {
			mainEntity = mainEntities.get(i);
			mainValues = reflectBeanToAry(mainEntity, mainProps, null, null);
			if (isOneToMany) {
				itemList = new ArrayList();
			}
			itemSize = 0;
			for (int j = 0; j < itemEntities.size(); j++) {
				itemEntity = itemEntities.get(j);
				mappedFieldValues = reflectBeanToAry(itemEntity, mappedFields, null, null);
				isEqual = true;
				for (int k = 0; k < fieldLength; k++) {
					if (null == mainValues[k] || !mainValues[k].equals(mappedFieldValues[k])) {
						isEqual = false;
						break;
					}
				}
				if (isEqual) {
					if (isOneToMany) {
						itemList.add(itemEntity);
					} // oneToOne 直接赋值
					else {
						// update 2022-5-18 增加oneToOne 级联数据校验
						if (itemSize > 0) {
							throw new DataAccessException(
									"请检查对象:" + mainEntity.getClass().getName() + "中的@OneToOne级联配置,级联查出的数据为>1条,不符合预期!");
						}
						setProperty(mainEntity, property, itemEntity);
					}
					// 屏蔽掉，兼容ManyToOne、ManyToMany 场景
					// itemEntities.remove(j);
					// j--;
					itemSize++;
				}
			}
			if (isOneToMany && (itemList != null && !itemList.isEmpty())) {
				setProperty(mainEntity, property, itemList);
			}
		}
	}

	/**
	 * @TODO 解析类中的@OneToOne 和@OneToMany注解，服务sql查询结果按对象层次结构进行封装
	 * @param entityClass
	 * @return
	 */
	private static Field[] parseCascadeFields(Class entityClass) {
		Set<String> fieldSet = new HashSet<String>();
		List<Field> cascadeFields = new ArrayList<Field>();
		Class classType = entityClass;
		String fieldName;
		while (classType != null && !classType.equals(Object.class)) {
			for (Field field : classType.getDeclaredFields()) {
				fieldName = field.getName().toLowerCase();
				if (!fieldSet.contains(fieldName) && (field.getAnnotation(OneToMany.class) != null
						|| field.getAnnotation(OneToOne.class) != null)) {
					cascadeFields.add(field);
					fieldSet.add(fieldName);
				}
			}
			// 支持多级继承关系
			classType = classType.getSuperclass();
		}
		return cascadeFields.toArray(new Field[cascadeFields.size()]);
	}

	/**
	 * @TODO 获取类的级联关系
	 * @param entityClass
	 * @return
	 */
	public static List<TableCascadeModel> getCascadeModels(Class entityClass) {
		String className = entityClass.getName();
		List<TableCascadeModel> result = cascadeModels.get(className);
		if (result == null) {
			result = new ArrayList<TableCascadeModel>();
			Field[] cascadeFields = parseCascadeFields(entityClass);
			for (Field field : cascadeFields) {
				TableCascadeModel cascadeModel = new TableCascadeModel();
				cascadeModel.setProperty(field.getName());
				cascadeModel.setMappedType(
						(Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]);
				OneToMany oneToMany = field.getAnnotation(OneToMany.class);
				OneToOne oneToOne = field.getAnnotation(OneToOne.class);
				if (oneToMany != null) {
					cascadeModel.setCascadeType(1);
					cascadeModel.setFields(oneToMany.fields());
					cascadeModel.setMappedFields(oneToMany.mappedFields());
				} else {
					cascadeModel.setCascadeType(2);
					cascadeModel.setFields(oneToOne.fields());
					cascadeModel.setMappedFields(oneToOne.mappedFields());
				}
				result.add(cascadeModel);
			}
			cascadeModels.put(className, result);
		}
		return result;
	}

	public static KeyAndIndex getKeyAndIndex(String property) {
		if (property == null) {
			return null;
		}
		if (!StringUtil.matches(property, ARRAY_PATTERN)) {
			return null;
		}
		KeyAndIndex result = new KeyAndIndex();
		int lastIndex = property.lastIndexOf("[");
		result.setKey(property.substring(0, lastIndex));
		result.setIndex(Integer.parseInt(property.substring(lastIndex + 1, property.length() - 1)));
		return result;
	}

	public static Object getAryPropValue(Object result, int index) {
		if (result == null) {
			return null;
		}
		Object[] ary = null;
		if (result instanceof Object[]) {
			ary = (Object[]) result;
		} else if (result instanceof Collection) {
			ary = ((Collection) result).toArray();
		}
		if (ary != null && ary.length > index) {
			return ary[index];
		}
		return null;
	}
}
