Created
April 19, 2012 07:21
-
-
Save weirhp/2419358 to your computer and use it in GitHub Desktop.
获得方法形参名称列表By ASM (Java)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.weirhp; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import org.objectweb.asm.ClassReader; | |
import org.objectweb.asm.tree.ClassNode; | |
import org.objectweb.asm.tree.LocalVariableNode; | |
import org.objectweb.asm.tree.MethodNode; | |
/** | |
* 通过读取Class文件,获得方法形参名称列表 | |
* | |
* @author weirhp(weirhp@gmail.com) | |
* 修改自wendal的https://gist.github.com/2011728 | |
*/ | |
public class MethodParamNamesScanerByASM { | |
public static void main(String[] args) throws IOException { | |
Map<String, List<String>> map = getParamNames(new FileInputStream( | |
"D:\\project\\dodopipe.ui.osgi.example.service\\target\\classes\\dodopipe\\ui\\osgi\\example\\service\\impl\\RedmineServiceImpl.class")); | |
for (String key : map.keySet()) { | |
System.out.println(key); | |
System.out.print("\t"); | |
for (String str : map.get(key)) { | |
System.out.print(str + "|"); | |
} | |
System.out.println(); | |
} | |
} | |
/** | |
* 获取Method的形参名称列表 | |
* | |
* @param method | |
* 需要解析的方法 | |
* @return 形参名称列表,如果没有调试信息,将返回null | |
*/ | |
public static List<String> getParamNames(Method method) { | |
try { | |
int size = method.getParameterTypes().length; | |
if (size == 0) | |
return new ArrayList<String>(0); | |
List<String> list = getParamNames(method.getDeclaringClass()).get( | |
getKey(method)); | |
if (list != null && list.size() != size) | |
return list.subList(0, size); | |
return list; | |
} catch (Throwable e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* 获取一个类的所有方法/构造方法的形参名称Map | |
* | |
* @param klass | |
* 需要解析的类 | |
* @return 所有方法/构造方法的形参名称Map | |
* @throws IOException | |
* 如果有任何IO异常,不应该有,如果是本地文件,那100%遇到bug了 | |
*/ | |
public static Map<String, List<String>> getParamNames(Class<?> klass) | |
throws IOException { | |
InputStream in = klass.getResourceAsStream("/" | |
+ klass.getName().replace('.', '/') + ".class"); | |
return getParamNames(in); | |
} | |
public static Map<String, List<String>> getParamNames(InputStream in) | |
throws IOException { | |
ClassReader cr = new ClassReader(in); | |
ClassNode cn = new ClassNode(); | |
cr.accept(cn, ClassReader.EXPAND_FRAMES); | |
List<MethodNode> methods = cn.methods; | |
Map<String, List<String>> rtn = new HashMap<String, List<String>>(); | |
for (int i = 0; i < methods.size(); ++i) { | |
List<LocalVariable> varNames = new ArrayList<LocalVariable>(); | |
MethodNode method = methods.get(i); | |
List<LocalVariableNode> local_variables = method.localVariables; | |
for (int l = 0; l < local_variables.size(); l++) { | |
String varName = local_variables.get(l).name; | |
// index | |
int index = local_variables.get(l).index; | |
if (!"this".equals(varName)) // 非静态方法,第一个参数是this | |
varNames.add(new LocalVariable(index, varName)); | |
} | |
LocalVariable[] tmpArr = varNames.toArray(new LocalVariable[0]); | |
Arrays.sort(tmpArr); | |
List<String> list = new ArrayList<String>(); | |
for (LocalVariable var : tmpArr) { | |
list.add(var.name); | |
} | |
rtn.put(method.name + "," + method.desc, list); | |
} | |
return rtn; | |
} | |
static class LocalVariable implements Comparable<LocalVariable> { | |
public int index; | |
public String name; | |
public LocalVariable(int index, String name) { | |
this.index = index; | |
this.name = name; | |
} | |
public int compareTo(LocalVariable o) { | |
return this.index - o.index; | |
} | |
} | |
/** | |
* 获取Constructor的形参名称列表 | |
* | |
* @param constructor | |
* 需要解析的构造函数 | |
* @return 形参名称列表,如果没有调试信息,将返回null | |
*/ | |
public static List<String> getParamNames(Constructor<?> constructor) { | |
try { | |
int size = constructor.getParameterTypes().length; | |
if (size == 0) | |
return new ArrayList<String>(0); | |
List<String> list = getParamNames(constructor.getDeclaringClass()) | |
.get(getKey(constructor)); | |
if (list != null && list.size() != size) | |
return list.subList(0, size); | |
return list; | |
} catch (Throwable e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* 传入Method或Constructor,获取getParamNames方法返回的Map所对应的key | |
*/ | |
public static String getKey(Object obj) { | |
StringBuilder sb = new StringBuilder(); | |
if (obj instanceof Method) { | |
sb.append(((Method) obj).getName()).append(','); | |
getDescriptor(sb, (Method) obj); | |
} else if (obj instanceof Constructor) { | |
sb.append("<init>,"); // 只有非静态构造方法才能用有方法参数的,而且通过反射API拿不到静态构造方法 | |
getDescriptor(sb, (Constructor<?>) obj); | |
} else | |
throw new RuntimeException("Not Method or Constructor!"); | |
return sb.toString(); | |
} | |
public static void getDescriptor(StringBuilder sb, Method method) { | |
sb.append('('); | |
for (Class<?> klass : method.getParameterTypes()) | |
getDescriptor(sb, klass); | |
sb.append(')'); | |
getDescriptor(sb, method.getReturnType()); | |
} | |
public static void getDescriptor(StringBuilder sb, | |
Constructor<?> constructor) { | |
sb.append('('); | |
for (Class<?> klass : constructor.getParameterTypes()) | |
getDescriptor(sb, klass); | |
sb.append(')'); | |
sb.append('V'); | |
} | |
/** 本方法来源于ow2的asm库的Type类 */ | |
public static void getDescriptor(final StringBuilder buf, final Class<?> c) { | |
Class<?> d = c; | |
while (true) { | |
if (d.isPrimitive()) { | |
char car; | |
if (d == Integer.TYPE) { | |
car = 'I'; | |
} else if (d == Void.TYPE) { | |
car = 'V'; | |
} else if (d == Boolean.TYPE) { | |
car = 'Z'; | |
} else if (d == Byte.TYPE) { | |
car = 'B'; | |
} else if (d == Character.TYPE) { | |
car = 'C'; | |
} else if (d == Short.TYPE) { | |
car = 'S'; | |
} else if (d == Double.TYPE) { | |
car = 'D'; | |
} else if (d == Float.TYPE) { | |
car = 'F'; | |
} else /* if (d == Long.TYPE) */{ | |
car = 'J'; | |
} | |
buf.append(car); | |
return; | |
} else if (d.isArray()) { | |
buf.append('['); | |
d = d.getComponentType(); | |
} else { | |
buf.append('L'); | |
String name = d.getName(); | |
int len = name.length(); | |
for (int i = 0; i < len; ++i) { | |
char car = name.charAt(i); | |
buf.append(car == '.' ? '/' : car); | |
} | |
buf.append(';'); | |
return; | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment