Java: Простой способ вытащить тупик метода из файлов класса в файле JAR? Отражение?

Я ищу способ получить список тупиков метода всех классов в файле банки. Я не уверен, где запустить... Позвольте мне использовать Reflection или Javassist или некоторые другие инструменты которого я еще не услышал!? По крайней мере, может быть возможно распаковать банку, декомпилировать файлы класса и сканирование с синтаксическим анализатором строки для методов, но я думаю, что это - самый самый грязный путь ;-)

Какие-либо идеи?

С уважением

6
задан djatomic 21 July 2010 в 00:04
поделиться

2 ответа

Основываясь на ответе aioobe , вы также можете использовать API дерева ASM (в отличие от API посетителя) для анализа содержимого файлов классов, содержащихся в вашем JAR-файле. Кроме того, вы можете читать файлы, содержащиеся в файле JAR, используя класс JarFile . Вот пример того, как это можно сделать:

Метод printMethodStubs принимает JarFile и продолжает распечатывать описания всех методов, содержащихся во всех файлах классов.

public void printMethodStubs(JarFile jarFile) throws Exception {
    Enumeration<JarEntry> entries = jarFile.entries();
    while (entries.hasMoreElements()) {
        JarEntry entry = entries.nextElement();

        String entryName = entry.getName();
        if (entryName.endsWith(".class")) {
            ClassNode classNode = new ClassNode();

            InputStream classFileInputStream = jarFile.getInputStream(entry);
            try {
                ClassReader classReader = new ClassReader(classFileInputStream);
                classReader.accept(classNode, 0);
            } finally {
                classFileInputStream.close();
            }

            System.out.println(describeClass(classNode));
        }
    }
}

Метод describeClass принимает объект ClassNode и переходит к описанию его и связанных с ним методов:

public String describeClass(ClassNode classNode) {
    StringBuilder classDescription = new StringBuilder();

    Type classType = Type.getObjectType(classNode.name);



    // The class signature (e.g. - "public class Foo")
    if ((classNode.access & Opcodes.ACC_PUBLIC) != 0) {
        classDescription.append("public ");
    }

    if ((classNode.access & Opcodes.ACC_PRIVATE) != 0) {
        classDescription.append("private ");
    }

    if ((classNode.access & Opcodes.ACC_PROTECTED) != 0) {
        classDescription.append("protected ");
    }

    if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
        classDescription.append("abstract ");
    }

    if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {
        classDescription.append("interface ");
    } else {
        classDescription.append("class ");
    }

    classDescription.append(classType.getClassName()).append("\n");
    classDescription.append("{\n");



    // The method signatures (e.g. - "public static void main(String[]) throws Exception")
    @SuppressWarnings("unchecked")
    List<MethodNode> methodNodes = classNode.methods;

    for (MethodNode methodNode : methodNodes) {
        String methodDescription = describeMethod(methodNode);
        classDescription.append("\t").append(methodDescription).append("\n");
    }



    classDescription.append("}\n");

    return classDescription.toString();
}

Метод describeMethod принимает MethodNode и возвращает строку, описывающую сигнатуру метода:

public String describeMethod(MethodNode methodNode) {
    StringBuilder methodDescription = new StringBuilder();

    Type returnType = Type.getReturnType(methodNode.desc);
    Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);

    @SuppressWarnings("unchecked")
    List<String> thrownInternalClassNames = methodNode.exceptions;

    if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) {
        methodDescription.append("public ");
    }

    if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) {
        methodDescription.append("private ");
    }

    if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) {
        methodDescription.append("protected ");
    }

    if ((methodNode.access & Opcodes.ACC_STATIC) != 0) {
        methodDescription.append("static ");
    }

    if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) {
        methodDescription.append("abstract ");
    }

    if ((methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0) {
        methodDescription.append("synchronized ");
    }

    methodDescription.append(returnType.getClassName());
    methodDescription.append(" ");
    methodDescription.append(methodNode.name);

    methodDescription.append("(");
    for (int i = 0; i < argumentTypes.length; i++) {
        Type argumentType = argumentTypes[i];
        if (i > 0) {
            methodDescription.append(", ");
        }
        methodDescription.append(argumentType.getClassName());
    }
    methodDescription.append(")");

    if (!thrownInternalClassNames.isEmpty()) {
        methodDescription.append(" throws ");
        int i = 0;
        for (String thrownInternalClassName : thrownInternalClassNames) {
            if (i > 0) {
                methodDescription.append(", ");
            }
            methodDescription.append(Type.getObjectType(thrownInternalClassName).getClassName());
            i++;
        }
    }

    return methodDescription.toString();
}
11
ответ дан 9 December 2019 в 20:41
поделиться

Лучший способ, который я могу придумать, - это использовать структуру байт-кода ASM. Тогда, по крайней мере, вам не нужно было бы выполнять декомпиляцию-вывод с помощью синтаксического анализатора строк.Фактически, получение заглушек методов должно быть похоже на 20-строчную реализацию одного из их Visitor-интерфейсов.

Я сам использовал его для перезаписи байт-кода, и он довольно простой и понятный (особенно если вы просто читаете файлы классов).

http://asm.ow2.org/

1
ответ дан 9 December 2019 в 20:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: