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

com.ajaxjs.util.ReflectUtil Maven / Gradle / Ivy

There is a newer version: 1.2.6
Show newest version
/**
 * Copyright Sp42 [email protected] 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.ajaxjs.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import com.ajaxjs.util.logger.LogHelper;

/**
 * 反射工具包
 * 
 * @author sp42 [email protected]
 */
public class ReflectUtil {
	private static final LogHelper LOGGER = LogHelper.getLog(ReflectUtil.class);

	/**
	 * 根据类创建实例,可传入构造器参数。
	 * 
	 * @param clz  类对象
	 * @param args 获取指定参数类型的构造函数,这里传入我们想调用的构造函数所需的参数。可以不传。
	 * @return 对象实例
	 */
	public static  T newInstance(Class clz, Object... args) {
		if (clz.isInterface()) {
			LOGGER.warning("所传递的class类型参数为接口,无法实例化");
			return null;
		}

		if (args == null || args.length == 0) {
			try {
				return clz.newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				LOGGER.warning(e);
			}
		}

		// 获取构造器
		Constructor constructor = getConstructor(clz, args2class(args));
		return newInstance(constructor, args);
	}

	/**
	 * 根据构造器创建实例
	 * 
	 * @param constructor 类构造器
	 * @param args        获取指定参数类型的构造函数,这里传入我们想调用的构造函数所需的参数。可以不传。
	 * @return 对象实例
	 */
	public static  T newInstance(Constructor constructor, Object... args) {
		try {
			return constructor.newInstance(args); // 实例化
		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			LOGGER.warning(e, "实例化对象失败:" + constructor.getDeclaringClass());
			return null;
		}
	}

	/**
	 * 传入的类是否有带参数的构造器
	 * 
	 * @param clz 类对象
	 * @return true 表示为有带参数
	 */
	public static boolean hasArgsCon(Class clz) {
		Constructor[] constructors = clz.getConstructors();
		for (Constructor constructor : constructors) {
			if (constructor.getParameterTypes().length != 0)
				return true;
		}

		return false;
	}
	/**
	 * 根据类全称创建实例,并转换到其接口的类型
	 * 
	 * @param className 实际类的类型
	 * @param clazz     接口类型
	 * @return 对象实例
	 */
	// @SuppressWarnings("unchecked")
	// public static  T newInstance(String className, Class clazz) {
	// Class clz = getClassByName(className);
	// return clazz != null ? (T) newInstance(clz) : null;
	// }

	/**
	 * 根据类全称创建实例
	 * 
	 * @param clzName 类全称
	 * @param args    根据构造函数,创建指定类型的对象,传入的参数个数需要与上面传入的参数类型个数一致
	 * @return 对象实例,因为传入的类全称是字符串,无法创建泛型 T,所以统一返回 Object
	 */
	public static Object newInstance(String clzName, Object... args) {
		Class clazz = getClassByName(clzName);
		return clazz != null ? newInstance(clazz, args) : null;
	}

	/**
	 * 获取类的构造器,可以支持重载的构造器(不同参数的构造器)
	 * 
	 * @param clz        类对象
	 * @param argClasses 指定构造函数的参数类型,这里传入我们想调用的构造函数所需的参数类型
	 * @return 类的构造器
	 */
	public static  Constructor getConstructor(Class clz, Class... argClasses) {
		try {
			return argClasses != null ? clz.getConstructor(argClasses) : clz.getConstructor();
		} catch (NoSuchMethodException e) {
			LOGGER.warning(e, "找不到这个 {0} 类的构造器。", clz.getName());
		} catch (SecurityException e) {
			LOGGER.warning(e);
		}

		return null;
	}

	/**
	 * 根据类名字符串获取类对象
	 * 
	 * @param className 类全称
	 * @return 类对象
	 */
	public static Class getClassByName(String className) {
		try {
			return Class.forName(className);
		} catch (ClassNotFoundException e) {
			LOGGER.warning(e, "找不到这个类:{0}。", className);
		}

		return null;
	}

	/**
	 * 根据类名字符串获取类对象,可强类型转换类型
	 * 
	 * @param className 类全称
	 * @param clz       要转换的目标类型
	 * @return 类对象
	 */
	@SuppressWarnings("unchecked")
	public static  Class getClassByName(String className, Class clz) {
		Class c = getClassByName(className);
		return c == null ? null : (Class) getClassByName(className);
	}

	/**
	 * 把参数转换为类对象列表
	 * 
	 * @param args 可变参数列表
	 * @return 类对象列表
	 */
	public static Class[] args2class(Object[] args) {
		Class[] clazzes = new Class[args.length];

		for (int i = 0; i < args.length; i++)
			clazzes[i] = args[i].getClass();

		return clazzes;
	}

	/**
	 * 已知接口类型,获取它的 class
	 * 
	 * @param type 接口类型
	 * @return 接口的类对象
	 */
	public static Class getClassByInterface(Type type) {
		String className = type.toString();
		className = className.replaceAll("<.*>$", "").replaceAll("(class|interface)\\s", ""); // 不要泛型的字符

		return getClassByName(className);
	}

	/**
	 * 获取某个类的所有接口
	 * 
	 * @param clz 目标类
	 * @return 类的所有接口
	 */
	public static Class[] getDeclaredInterface(Class clz) {
		List> fields = new ArrayList<>();

		for (; clz != Object.class; clz = clz.getSuperclass()) {
			Class[] currentInterfaces = clz.getInterfaces();
			fields.addAll(Arrays.asList(currentInterfaces));
		}

		return fields.toArray(new Class[fields.size()]);
	}

	/////////////// Methods ///////////////////////

	/**
	 * 根据类、方法的字符串和参数列表获取方法对象,支持重载的方法
	 * 
	 * @param obj    可以是实例对象,也可以是类对象
	 * @param method 方法名称
	 * @param args   明确的参数类型列表
	 * @return 匹配的方法对象,null 表示找不到
	 */
	public static Method getMethod(Object obj, String method, Class... args) {
		Class cls = obj instanceof Class ? (Class) obj : obj.getClass();

		try {
			return CommonUtil.isNull(args) ? cls.getMethod(method) : cls.getMethod(method, args);
		} catch (NoSuchMethodException | SecurityException e) {
			String str = "";
			for (Class clz : args)
				str += clz.getName();

			LOGGER.warning("类找不到这个方法 {0}.{1}({2})。", cls.getName(), method, str.equals("") ? "void" : str);
			return null;
		}
	}

	/**
	 * 
	 * 根据方法名称和参数列表查找方法。注意参数对象类型由于没有向上转型会造成不匹配而找不到方法,这时应使用上一个方法或
	 * getMethodByUpCastingSearch()
	 * 
	 * @param obj    实例对象
	 * @param method 方法名称
	 * @param args   对应重载方法的参数列表
	 * @return 匹配的方法对象,null 表示找不到
	 */
	public static Method getMethod(Object obj, String method, Object... args) {
		if (!CommonUtil.isNull(args)) {
			return getMethod(obj, method, args2class(args));
		} else
			return getMethod(obj, method);
	}

	/**
	 * 根据方法名称和参数列表查找方法。自动循环参数类型向上转型。仅支持一个参数。
	 * 
	 * @param clz    实例对象的类对象
	 * @param method 方法名称
	 * @param arg    参数对象,可能是子类或接口,所以要在这里找到对应的方法,当前只支持单个参数;且不能传 Class,必须为对象
	 * @return 匹配的方法对象,null 表示找不到
	 */
	public static Method getMethodByUpCastingSearch(Class clz, String method, Object arg) {
		for (Class clazz = arg.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				// return cls.getDeclaredMethod(methodName, clazz);
				return clz.getMethod(method, clazz); // 用 getMethod 代替更好?
			} catch (NoSuchMethodException | SecurityException e) {
				// 这里的异常不能抛出去。 如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(), 最后就不会进入到父类中了
			}
		}

		return null;
	}

	/**
	 * 循环 object 向上转型(接口)
	 * 
	 * @param clz    主类
	 * @param method 方法名称
	 * @param arg    参数对象,可能是子类或接口,所以要在这里找到对应的方法,当前只支持单个参数
	 * @return 方法对象
	 */
	public static Method getDeclaredMethodByInterface(Class clz, String method, Object arg) {
		Method methodObj = null;

		for (Class clazz = arg.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
			Type[] intfs = clazz.getGenericInterfaces();

			if (intfs.length != 0) { // 有接口!
				try {
					for (Type intf : intfs) {
						// 旧方法,现在不行,不知道之前怎么可以的 methodObj = hostClazz.getDeclaredMethod(method,
						// (Class)intf);
						// methodObj = cls.getMethod(methodName,
						// ReflectNewInstance.getClassByInterface(intf));
						methodObj = getSuperClassDeclaredMethod(clz, method, getClassByInterface(intf));

						if (methodObj != null)
							return methodObj;
					}
				} catch (Exception e) {
					LOGGER.warning(e);
				}
			} else {
				// 无实现的接口
			}
		}

		return null;
	}

	/**
	 * 查找对象父类身上指定的方法
	 * 
	 * @param clz    主类
	 * @param method 方法名称
	 * @param argClz 参数类引用
	 * @return 匹配的方法对象,null 表示找不到
	 */
	public static Method getSuperClassDeclaredMethod(Class clz, String method, Class argClz) {
		for (; clz != Object.class; clz = clz.getSuperclass()) {
			try {
				return clz.getDeclaredMethod(method, argClz);
			} catch (NoSuchMethodException | SecurityException e) {
			}
		}

		return null;
	}

	/**
	 * 查找对象父类身上指定的方法(注意该方法不需要校验参数类型是否匹配,故有可能不是目标方法,而造成异常,请谨慎使用)
	 * 
	 * @param clz    主类
	 * @param method 方法名称
	 * @return 匹配的方法对象,null 表示找不到
	 */
	public static Method getSuperClassDeclaredMethod(Class clz, String method) {
		for (; clz != Object.class; clz = clz.getSuperclass()) {
			for (Method m : clz.getDeclaredMethods()) {
				if (m.toString().contains(method)) {
					return m;
				}
			}
		}

		return null;
	}

	/**
	 * 调用方法
	 * 
	 * @param instance 对象实例,bean
	 * @param method   方法对象
	 * @param args     参数列表
	 * @return 执行结果
	 * @throws Throwable
	 */
	public static Object executeMethod_Throwable(Object instance, Method method, Object... args) throws Throwable {
		if (instance == null || method == null)
			return null;

		try {
			return args == null || args.length == 0 ? method.invoke(instance) : method.invoke(instance, args);
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
			Throwable e;

			if (e1 instanceof InvocationTargetException) {
				e = ((InvocationTargetException) e1).getTargetException();
				System.err.println("反射执行方法异常!所在类:" + instance.getClass().getName() + "方法:" + method.getName());
				throw e;
			}

			throw e1;
		}
	}

	/**
	 * 获取实际抛出的那个异常对象。 InvocationTargetException 太过于宽泛,在 trouble
	 * shouting的时候,不能给人非常直观的信息 AOP 的缘故,不能直接捕获原来的异常,要不断 e.getCause()....
	 * 
	 * @param e 异常对象
	 * @return 实际异常对象
	 */
	public static Throwable getUnderLayerErr(Throwable e) {
		while (e.getClass().equals(InvocationTargetException.class)
				|| e.getClass().equals(UndeclaredThrowableException.class)) {
			e = e.getCause();
		}

		return e;
	}

	/**
	 * 获取实际抛出的那个异常对象,并去掉前面的包名。
	 * 
	 * @param e 异常对象
	 * @return 实际异常对象信息
	 */
	public static String getUnderLayerErrMsg(Throwable e) {
		String msg = getUnderLayerErr(e).toString();

		return msg.replaceAll("^[^:]*:\\s?", "");
	}

	/**
	 * 调用方法,该方法不会抛出异常
	 * 
	 * @param instance 对象实例,bean
	 * @param method   方法对象
	 * @param args     参数列表
	 * @return 执行结果
	 */
	public static Object executeMethod(Object instance, Method method, Object... args) {
		try {
			return executeMethod_Throwable(instance, method, args);
		} catch (Throwable e) {
			return null;
		}
	}

	/**
	 * 调用方法
	 * 
	 * @param instnace 对象实例,bean
	 * @param method   方法对象名称
	 * @param args     参数列表
	 * @return 执行结果
	 */
	public static Object executeMethod(Object instnace, String method, Object... args) {
		// 没有方法对象,先找到方法对象。可以支持方法重载,按照参数列表
		Class[] clazzes = args2class(args);
		Method methodObj = getMethod(instnace.getClass(), method, clazzes);

		return methodObj != null ? executeMethod(instnace, methodObj, args) : null;
	}

	/**
	 * 调用方法。 注意获取方法对象,原始类型和包装类型不能混用,否则得不到正确的方法, 例如 Integer 不能与 int 混用。 这里提供一个
	 * argType 的参数,指明参数类型为何。
	 * 
	 * @param instnace 对象实例
	 * @param method   方法名称
	 * @param argType  参数类型
	 * @param argValue 参数值
	 * @return 执行结果
	 */
	public static Object executeMethod(Object instnace, String method, Class argType, Object argValue) {
		Method m = getMethod(instnace, method, argType);
		if (m != null)
			return executeMethod(instnace, m, argValue);

		return null;
	}

	/**
	 * 执行静态方法
	 * 
	 * @param method 方法对象
	 * @param args   方法参数列表
	 * @return 执行结果
	 */
	public static Object executeStaticMethod(Method method, Object... args) {
		if (isStaticMethod(method)) {
			try {
				return executeMethod_Throwable(new Object(), method, args);
			} catch (Throwable e) {
				LOGGER.warning(e);
			}
		} else {
			LOGGER.warning("这不是一个静态方法:" + method);
		}

		return null;
	}

	/**
	 * 是否静态方法
	 * 
	 * @param method 方法对象
	 * @return true 表示为静态方法
	 */
	public static boolean isStaticMethod(Method method) {
		return Modifier.isStatic(method.getModifiers());
	}

	// --------------------------------------------------------------------------------------------------
	// -----------------------------------------------BeanUtils------------------------------------------
	// --------------------------------------------------------------------------------------------------

	/**
	 * 将第一个字母大写
	 * 
	 * @param str 字符串
	 * @return 字符串
	 */
	public static String firstLetterUpper(String str) {
		// return str.substring(0, 1).toUpperCase() + str.substring(1); // 另外一种写法
		return Character.toString(str.charAt(0)).toUpperCase() + str.substring(1);
	}

	/**
	 * 根据方法名称来截取属性名称,例如把 getter 的 getXxx() 转换为 xxx 的字段名
	 * 
	 * @param method 方法名称
	 * @param action set|get
	 * @return 属性名称
	 */
	public static String getFieldName(String method, String action) {
		method = method.replace(action, "");
		return Character.toString(method.charAt(0)).toLowerCase() + method.substring(1);
	}

	/**
	 * 调用 bean 对象的 setter 方法
	 * 
	 * @param bean  Bean 对象
	 * @param name  属性名称,前缀不要带 set
	 * @param value 要设置的属性值
	 */
	public static void setProperty(Object bean, String name, Object value) {
		String setMethodName = "set" + firstLetterUpper(name);

		Objects.requireNonNull(bean, bean + "执行:" + setMethodName + " 未发现类");
//		Objects.requireNonNull(value, bean + "执行:" + setMethodName + " 未发现参数 value");

		Class clazz = bean.getClass();

		// 要把参数父类的也包括进来
		Method method = getMethodByUpCastingSearch(clazz, setMethodName, value);

		// 如果没找到,那就试试接口的……
		if (method == null)
			method = getDeclaredMethodByInterface(clazz, setMethodName, value);

		// 如果没找到,那忽略参数类型,只要匹配方法名称即可。这会发生在:由于被注入的对象有可能经过了 AOP 的动态代理,所以不能通过上述逻辑找到正确的方法
		if (method == null) {
			method = getSuperClassDeclaredMethod(clazz, setMethodName);
		}

		// 最终还是找不到
		Objects.requireNonNull(method, clazz.getName() + " 找不到目标方法!" + setMethodName);

		executeMethod(bean, method, value);
	};
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy