/*
* Copyright (c) 2005-2012 springside.org.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
package com.ludii.excel.utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
/**
* 反射工具类.
* 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
*
* @author calvin、ThinkGem
* @version 2015-11-12
*/
public class ReflectUtils {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private final static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
private final static String PROPERTY_NAME_SEPARATOR_CHARS = ".";
/**
* 调用Getter方法,
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, PROPERTY_NAME_SEPARATOR_CHARS)) {
if (obj instanceof Map) {
object = ((Map) obj).get(name);
} else {
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, methodName, new Class[]{}, new Object[]{});
}
}
return (E) object;
}
/**
* 调用Setter方法,仅匹配方法名,
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, PROPERTY_NAME_SEPARATOR_CHARS);
for (int i = 0; i < names.length; i++) {
if (i < names.length - 1) {
if (obj instanceof Map) {
object = ((Map) obj).get(names[i]);
} else {
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = invokeMethod(object, methodName, new Class[]{}, new Object[]{});
// 如果 getSession 获取对象为空,并且返回值类型继承自 BaseEntity,则 new 对象,并通过 setSession 赋予它
if (childObj == null && object != null) {
Method method = getAccessibleMethod(object, methodName);
if (method != null) {
Class> returnType = method.getReturnType();
try {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[]{childObj});
} catch (Exception e) {
e.printStackTrace();
}
}
}
object = childObj;
}
} else {
if (obj instanceof Map) {
((Map) obj).put(names[i], value);
} else {
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[]{value});
}
}
}
}
/**
* 直接调用对象方法,无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用,
* 同时匹配方法名+参数类型,
* 支持静态类及方法调用
*/
public static E invokeMethod(final Object obj, final String methodName, final Class>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null) {
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
//noinspection unchecked
return (E) method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + Arrays.toString(args) + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法,无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用,
* 只匹配函数名,如果有多个同名函数调用第一个,
* 支持静态类及方法调用
*/
@SuppressWarnings("UnusedReturnValue")
public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++) {
if (args[i] != null && !args[i].getClass().equals(cs[i])) {
if (cs[i] == String.class) {
args[i] = ObjectUtils.toString(args[i]);
if (StringUtils.endsWith((String) args[i], ".0")) {
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
} else if (cs[i] == Integer.class) {
args[i] = ObjectUtils.toInteger(args[i]);
} else if (cs[i] == Long.class) {
args[i] = ObjectUtils.toLong(args[i]);
} else if (cs[i] == Double.class) {
args[i] = ObjectUtils.toDouble(args[i]);
} else if (cs[i] == Float.class) {
args[i] = ObjectUtils.toFloat(args[i]);
} else if (cs[i] == Date.class) {
if (args[i] instanceof String) {
args[i] = DateUtils.parseDate(args[i]);
} else {
// POI Excel 日期格式转换
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}
}
}
//noinspection unchecked
return (E) method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + Arrays.toString(args) + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型,获取对象的DeclaredMethod,并强制设置为可访问,
* 如向上转型到Object仍无法找到,返回null,
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况,先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class>... parameterTypes) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Class> clazz = obj.getClass();
if (clazz == Class.class) {
clazz = (Class>) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class> searchType = clazz; searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
// new add
}
}
return null;
}
/**
* 循环向上转型,获取对象的DeclaredMethod,并强制设置为可访问,
* 如向上转型到Object仍无法找到,返回null,
* 只匹配函数名。
* 用于方法需要被多次调用的情况,先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Class> clazz = obj.getClass();
if (clazz == Class.class) {
clazz = (Class>) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class> searchType = clazz; searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method) {
//noinspection AlibabaAvoidComplexCondition
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* 将反射时的checked exception转换为unchecked exception
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(msg, e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}
}