package org.nutz.lang.util; import java.io.BufferedInputStream; import java.io.DataInputStream; 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.HashMap; import java.util.List; import java.util.Map; import org.nutz.lang.Encoding; import org.nutz.lang.Streams; public class ClassMetaReader { //--------------------------------------------------------------------------------------------------- /** * 获取一个类的所有方法/构造方法的形参名称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"); try { if (in == null) return new HashMap<String, List<String>>(); return build(in).paramNames; } finally { Streams.safeClose(in); } } public static ClassMeta build(InputStream in) throws IOException { ClassMeta meta = new ClassMeta(); DataInputStream dis = new DataInputStream(new BufferedInputStream(in)); Map<String, List<String>> names = new HashMap<String, List<String>>(); Map<String, Integer> lines = new HashMap<String, Integer>(); Map<Integer, String> strs = new HashMap<Integer, String>(); Map<Integer, Integer> classIndex = new HashMap<Integer, Integer>(); dis.skipBytes(4);//Magic dis.skipBytes(2);//副版本号 dis.skipBytes(2);//主版本号 //读取常量池 int constant_pool_count = dis.readUnsignedShort(); for (int i = 0; i < (constant_pool_count - 1); i++) { byte flag = dis.readByte(); switch (flag) { case 7://CONSTANT_Class: int z = dis.readUnsignedShort(); classIndex.put(i+1, z); break; case 9://CONSTANT_Fieldref: case 10://CONSTANT_Methodref: case 11://CONSTANT_InterfaceMethodref: dis.skipBytes(2); dis.skipBytes(2); break; case 8://CONSTANT_String: dis.skipBytes(2); break; case 3://CONSTANT_Integer: case 4://CONSTANT_Float: dis.skipBytes(4); break; case 5://CONSTANT_Long: case 6://CONSTANT_Double: dis.skipBytes(8); i++;//必须跳过一个,这是class文件设计的一个缺陷,历史遗留问题 break; case 12://CONSTANT_NameAndType: dis.skipBytes(2); dis.skipBytes(2); break; case 1://CONSTANT_Utf8: int len = dis.readUnsignedShort(); byte[] data = new byte[len]; dis.readFully(data); strs.put(i + 1, new String(data, Encoding.UTF8));//必然是UTF8的 break; case 15://CONSTANT_MethodHandle: dis.skipBytes(1); dis.skipBytes(2); break; case 16://CONSTANT_MethodType: dis.skipBytes(2); break; case 18://CONSTANT_InvokeDynamic: dis.skipBytes(2); dis.skipBytes(2); break; default: throw new RuntimeException("Impossible!! flag="+flag); } } dis.skipBytes(2);//版本控制符 //类名 int z = dis.readUnsignedShort(); meta.type = strs.get(classIndex.get(z)); if (meta.type != null) { meta.type = meta.type.replace('/', '.'); } dis.skipBytes(2);//超类 //跳过接口定义 int interfaces_count = dis.readUnsignedShort(); dis.skipBytes(2 * interfaces_count);//每个接口数据,是2个字节 //跳过字段定义 int fields_count = dis.readUnsignedShort(); for (int i = 0; i < fields_count; i++) { dis.skipBytes(2); dis.skipBytes(2); dis.skipBytes(2); int attributes_count = dis.readUnsignedShort(); for (int j = 0; j < attributes_count; j++) { dis.skipBytes(2);//跳过访问控制符 int attribute_length = dis.readInt(); dis.skipBytes(attribute_length); } } //开始读取方法 int methods_count = dis.readUnsignedShort(); for (int i = 0; i < methods_count; i++) { dis.skipBytes(2); //跳过访问控制符 String methodName = strs.get(dis.readUnsignedShort()); String descriptor = strs.get(dis.readUnsignedShort()); short attributes_count = dis.readShort(); String key = methodName + "," + descriptor; for (int j = 0; j < attributes_count; j++) { String attrName = strs.get(dis.readUnsignedShort()); int attribute_length = dis.readInt(); if ("Code".equals(attrName)) { //形参只在Code属性中 dis.skipBytes(2); dis.skipBytes(2); int code_len = dis.readInt(); dis.skipBytes(code_len); //跳过具体代码 int exception_table_length = dis.readUnsignedShort(); dis.skipBytes(8 * exception_table_length); //跳过异常表 int code_attributes_count = dis.readUnsignedShort(); for (int k = 0; k < code_attributes_count; k++) { int str_index = dis.readUnsignedShort(); String codeAttrName = strs.get(str_index); int code_attribute_length = dis.readInt(); if ("LocalVariableTable".equals(codeAttrName)) {//形参在LocalVariableTable属性中 int local_variable_table_length = dis.readUnsignedShort(); List<String> varNames = new ArrayList<String>(local_variable_table_length); for (int l = 0; l < local_variable_table_length; l++) { dis.skipBytes(2); dis.skipBytes(2); String varName = strs.get(dis.readUnsignedShort()); dis.skipBytes(2); dis.skipBytes(2); if (!"this".equals(varName)) //非静态方法,第一个参数是this varNames.add(varName); } if (!names.containsKey(key)) names.put(key, varNames); } else if ("LineNumberTable".equals(codeAttrName)) { int len = dis.readUnsignedShort(); if (len > 0) { dis.skipBytes(2); int line = dis.readUnsignedShort(); dis.skipBytes(code_attribute_length - 6); lines.put(key, line); } } else dis.skipBytes(code_attribute_length); } } else if ("MethodParameters".equals(attrName)) { // JDK 8的参数名存储, 需要编译时加了-parameters 选项 // http://www.java-allandsundry.com/2013/12/java-8-parameter-name-at-runtime.html int paramCount = dis.readByte(); List<String> varNames = new ArrayList<String>(paramCount); for (int l = 0; l < paramCount; l++) { String varName = strs.get(dis.readUnsignedShort()); dis.skipBytes(2); if (!"this".equals(varName)) //非静态方法,第一个参数是this varNames.add(varName); } names.put(key, varNames); } else dis.skipBytes(attribute_length); } } dis.close(); meta.paramNames.putAll(names); meta.methodLines.putAll(lines); return meta; } /** * 传入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; } } } }