com.gitee.easyopen.util.FieldUtil Maven / Gradle / Ivy
package com.gitee.easyopen.util;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/**
* @author tanghc
*/
public class FieldUtil {
private static final Logger log = LoggerFactory.getLogger(FieldUtil.class);
private static final String CLASS_SUFFIX = ".class";
private FieldUtil() {
}
/**
* 判断这个字段是否是数字类型或字符串类型
*
* @param type 字段类型
* @return true:是数字或字符串类型
*/
public static boolean isNumberOrStringType(Class> type) {
if (type == String.class) {
return true;
}
if (type.getGenericSuperclass() == Number.class) {
return true;
}
if (type.isPrimitive()) {
return true;
}
return false;
}
/**
* 获取指定类指定方法的参数名
* @param clazz 要获取参数名的方法所属的类
* @param method 要获取参数名的方法
* @param index 参数索引,从0开始
* @return 返回指定类指定方法的参数名,没有返回空字符串
*/
public static String getMethodParameterName(Class> clazz, final Method method, int index) {
String[] names = getMethodParameterNamesByAsm(clazz, method);
if (names.length == 0) {
return "";
}
return names[index];
}
/**
* 获取指定类指定方法的参数名
*
* @param clazz 要获取参数名的方法所属的类
* @param method 要获取参数名的方法
* @return 按参数顺序排列的参数名列表,如果没有参数,则返回空数组
*/
public static String[] getMethodParameterNamesByAsm(Class> clazz, final Method method) {
final Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes == null || parameterTypes.length == 0) {
return new String[0];
}
final Type[] types = new Type[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
types[i] = Type.getType(parameterTypes[i]);
}
final String[] parameterNames = new String[parameterTypes.length];
// 解决clazz对象是cglib对象导致空指针异常
// 获取真实的class,如果是cglib类,则返回父类class
Class> realClass = ClassUtils.getUserClass(clazz);
String className = realClass.getName();
int lastDotIndex = className.lastIndexOf('.');
className = className.substring(lastDotIndex + 1) + CLASS_SUFFIX;
InputStream is = realClass.getResourceAsStream(className);
try {
ClassReader classReader = new ClassReader(is);
classReader.accept(new ClassVisitor(Opcodes.ASM6) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// 只处理指定的方法
Type[] argumentTypes = Type.getArgumentTypes(desc);
if (!method.getName().equals(name) || !Arrays.equals(argumentTypes, types)) {
return null;
}
return new MethodVisitor(Opcodes.ASM6) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
int i = index - 1;
// 如果是静态方法,则第一就是参数
// 如果不是静态方法,则第一个是"this",然后才是方法的参数
if (Modifier.isStatic(method.getModifiers())) {
i = index;
}
if (i >= 0 && i < parameterNames.length) {
parameterNames[i] = name;
}
super.visitLocalVariable(name, desc, signature, start,
end, index);
}
};
}
}, 0);
} catch (IOException e) {
log.error("生成asm失败,oriClass:{}, realClass:{} method:{}", clazz.getName(), realClass.getName(), method.toGenericString(), e);
}
return parameterNames;
}
}