解析 Jar 文件并找到类之间的关系? [英] Parse Jar file and find relationships between classes?

查看:40
本文介绍了解析 Jar 文件并找到类之间的关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何检测jar文件中的类是否正在扩展其他类,或者是否有对其他类对象的方法调用或其他类对象被创建?然后系统出哪个类继承哪个类,哪个类调用哪个类的方法.

How to detect whether the class from the jar file is extending other class or if there are method calls to other class objects or other class objects are created ? and then system out which class extend which class and which class called methods from which class .

我使用 Classparser 来解析 jar .这是我的代码的一部分:

Im using Classparser to parser the jar . here is part of my code :

        String jarfile = "C:\\Users\\OOOO\\Desktop\\Sample.Jar";

        jar = new JarFile(jarfile);
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            if (!entry.getName().endsWith(".class")) {
                continue;
            }

            ClassParser parser = new ClassParser(jarfile, entry.getName());
            JavaClass javaClass = parser.parse();

推荐答案

有人投票结束这个问题,因为这个问题太宽泛了".我不确定这是否是这里合适的关闭原因,但可能是,因为人们可以考虑这个问题(这是对 您之前的问题) 就像要求别人为您做一些工作一样.

Someone voted to close this question as "too broad". I'm not sure whether this is the appropriate close reason here, but it might be, because one could consider this question (which is a follow up to your previous question) as just asking others to do some work for you.

但是,要回答如何使用 BCEL 检测单个 JAR 文件中的类之间的引用的基本问题:

However, to answer the basic question of how to detect references between classes in a single JAR file with BCEL:

您可以从 JarFile 中获取 JavaClass 对象的列表.对于这些JavaClass 对象中的每一个,您可以检查Method 对象及其InstructionList.在这些指令中,您可以选择 InvokeInstruction 对象并进一步检查它们以找出在那里实际调用了哪个类的哪个方法.

You can obtain the list of JavaClass objects from the JarFile. For each of these JavaClass objects, you can inspect the Method objects and their InstructionList. Out of these instructions, you can select the InvokeInstruction objects and examine them further to find out which method on which class is actually invoked there.

以下程序打开一个 JAR 文件(出于显而易见的原因,它是 bcel-5.2.jar - 无论如何您都需要它......)并以上述方式处理它.对于 JAR 文件的每个 JavaClass,它会创建从所有引用的 JavaClass 对象到在这些对象上调用的 Method 列表的映射类,并相应地打印信息:

The following program opens a JAR file (for obvious reasons, it's the bcel-5.2.jar - you'll need it anyhow...) and processes it in the way described above. For each JavaClass of the JAR file, it creates a map from all referenced JavaClass objects to the list of the Methods that are invoked on these classes, and prints the information accordingly:

import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;

public class BCELRelationships
{
    public static void main(String[] args) throws Exception
    {
        JarFile jarFile = null;
        try
        {
            String jarName = "bcel-5.2.jar";
            jarFile = new JarFile(jarName);
            findReferences(jarName, jarFile);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (jarFile != null)
            {
                try
                {
                    jarFile.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void findReferences(String jarName, JarFile jarFile) 
        throws ClassFormatException, IOException, ClassNotFoundException
    {
        Map<String, JavaClass> javaClasses = 
            collectJavaClasses(jarName, jarFile);

        for (JavaClass javaClass : javaClasses.values())
        {
            System.out.println("Class "+javaClass.getClassName());
            Map<JavaClass, Set<Method>> references = 
                computeReferences(javaClass, javaClasses);
            for (Entry<JavaClass, Set<Method>> entry : references.entrySet())
            {
                JavaClass referencedJavaClass = entry.getKey();
                Set<Method> methods = entry.getValue();
                System.out.println(
                    "    is referencing class "+
                    referencedJavaClass.getClassName()+" by calling");
                for (Method method : methods)
                {
                    System.out.println(
                        "        "+method.getName()+" with arguments "+
                        Arrays.toString(method.getArgumentTypes()));
                }
            }
        }
    }

    private static Map<String, JavaClass> collectJavaClasses(
        String jarName, JarFile jarFile) 
            throws ClassFormatException, IOException
    {
        Map<String, JavaClass> javaClasses =
            new LinkedHashMap<String, JavaClass>();
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements())
        {
            JarEntry entry = entries.nextElement();
            if (!entry.getName().endsWith(".class"))
            {
                continue;
            }

            ClassParser parser = 
                new ClassParser(jarName, entry.getName());
            JavaClass javaClass = parser.parse();
            javaClasses.put(javaClass.getClassName(), javaClass);
        }
        return javaClasses;
    }

    public static Map<JavaClass, Set<Method>> computeReferences(
        JavaClass javaClass, Map<String, JavaClass> knownJavaClasses) 
            throws ClassNotFoundException
    {
        Map<JavaClass, Set<Method>> references = 
            new LinkedHashMap<JavaClass, Set<Method>>();
        ConstantPool cp = javaClass.getConstantPool();
        ConstantPoolGen cpg = new ConstantPoolGen(cp);
        for (Method m : javaClass.getMethods())
        {
            String fullClassName = javaClass.getClassName();
            String className = 
                fullClassName.substring(0, fullClassName.length()-6);
            MethodGen mg = new MethodGen(m, className, cpg);
            InstructionList il = mg.getInstructionList();
            if (il == null)
            {
                continue;
            }
            InstructionHandle[] ihs = il.getInstructionHandles();
            for(int i=0; i < ihs.length; i++) 
            {
                InstructionHandle ih = ihs[i];
                Instruction instruction = ih.getInstruction();
                if (!(instruction instanceof InvokeInstruction))
                {
                    continue;
                }
                InvokeInstruction ii = (InvokeInstruction)instruction;
                ReferenceType referenceType = ii.getReferenceType(cpg);
                if (!(referenceType instanceof ObjectType))
                {
                    continue;
                }

                ObjectType objectType = (ObjectType)referenceType;
                String referencedClassName = objectType.getClassName();
                JavaClass referencedJavaClass = 
                    knownJavaClasses.get(referencedClassName);
                if (referencedJavaClass == null)
                {
                    continue;
                }

                String methodName = ii.getMethodName(cpg);
                Type[] argumentTypes = ii.getArgumentTypes(cpg);
                Method method = 
                    findMethod(referencedJavaClass, methodName, argumentTypes);
                Set<Method> methods = references.get(referencedJavaClass);
                if (methods == null)
                {
                    methods = new LinkedHashSet<Method>();
                    references.put(referencedJavaClass, methods);
                }
                methods.add(method);
            }
        }
        return references;
    }

    private static Method findMethod(
        JavaClass javaClass, String methodName, Type argumentTypes[])
            throws ClassNotFoundException
    {
        for (Method method : javaClass.getMethods())
        {
            if (method.getName().equals(methodName))
            {
                if (Arrays.equals(argumentTypes, method.getArgumentTypes()))
                {
                    return method;
                }
            }
        }
        for (JavaClass superClass : javaClass.getSuperClasses())
        {
            Method method = findMethod(superClass, methodName, argumentTypes);
            if (method != null)
            {
                return method;
            }
        }
        return null;
    }
}

但是,请注意,此信息在任何意义上都可能不完整.例如,由于多态性,您可能不会总是检测到某个类的对象上调用了某个方法,因为它隐藏"在多态抽象之后.例如,在像

Note, however, that this information might not be complete in every sense. For example, due to polymorphism, you might not always detect that a method is called on an object of a certain class, because it is "hidden" behind the polymorphic abstraction. For example, in a code snippet like

void call() {
    MyClass m = new MyClass();
    callToString(m);
}
void callToString(Object object) {
    object.toString();
}

toString 的调用实际上发生在MyClass 的一个实例上.但是由于多态性,它只能被识别为对some Object"的这个方法的调用.

the call to toString actually happens on an instance of MyClass. But due to polymorphism, it can only be recognized as a call to this method on "some Object".

这篇关于解析 Jar 文件并找到类之间的关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆