有个需求,从Java的class文件中获取包名。我知道javap可以获取,但是想通过java的方式来获取。
不知道javap如何获取的,这里贴个链接:http://lydawen.iteye.com/blog/1874276
用纯Java的方式走了点弯路,这里也顺便提下:
首先,想到的是将class文件转为byte[],然后encodeHex,再解析。
说明下,这种思路是没有问题的(实现复杂),但是下面PackageFromBytes的做法不正确(某些情况下可行,具体原因读者自己分析)。
package org.hot2hot.utils;
import org.apache.commons.lang.StringUtils;
@Deprecated
public class PackageFromBytes {
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static String getPackage(byte[] clazz) {
StringBuilder pack = new StringBuilder();
//300 是根据包名的一般长度设置的。
char[] cs = encodeHex(clazz, 300);
int i = 32;
while(true) {
String hexStr = new String(cs, i, 2);
int c = Integer.parseInt(hexStr, 16);
pack.append((char)c);
i += 2;
if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c == 47 || c>= 48 && c <=57 || c == 36)) {
break;
}
}
return StringUtils.replace(pack.toString(), "/", ".");
}
private static char[] encodeHex(byte[] data, int think) {
int l = data.length;
l = think < l ? think : l;
char[] out = new char[l << 1];
for (int i = 0, j = 0; i < l; i++) {
out[j++] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4];
out[j++] = DIGITS_UPPER[0x0F & data[i]];
}
return out;
}
}
转变思路,com.sun.tools提供了ClassFile类,通过它可以得到常量池信息。
这里贴张图复习下:
于是就有了下面这段代码:
package org.hot2hot.utils;
import java.io.File;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
import com.sun.tools.classfile.ConstantPool.CPInfo;
import com.sun.tools.classfile.ConstantPoolException;
public class PackageFromClassFile {
public static String getPackage(File paramFile) {
try {
ClassFile classFile = ClassFile.read(paramFile);
CPInfo classInfo = classFile.constant_pool.get(classFile.this_class);
if(classInfo instanceof CONSTANT_Class_info) {
CPInfo cp = classFile.constant_pool.get(((CONSTANT_Class_info) classInfo).name_index);
if(cp instanceof CONSTANT_Utf8_info) {
return StringUtils.replace(((CONSTANT_Utf8_info)cp).value, "/", ".");
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ConstantPoolException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
File file = new File("/Users/jiaojianfeng/Documents/empleyment/clazz/A.class");
System.out.println(getPackage(file));
}
}
折腾。。。。。
如果有更简单的方法,望告知。