如何获得Java源代码的完整调用层次结构?

 大学教授也是砖家 发布于 2023-02-10 13:32

解释这有点棘手.我有一个A类:

public class A {
    private Integer a1;
    private Integer a2;
    // getters and setters.
}

有一个静态类B返回我的类A:

public static class B {
    public static A getCurrentA() {
        return a;
    }
}

我需要找到B返回的所有A类用法.所以让我们说C级呼叫c.setA(B.getCurrentA()),然后再进一步调用c.getA().getA2();,我想找到所有这些.

在真实场景中,我有217个不同的类调用B.getCurrentA().我不能手动跟踪Eclipse中的所有调用,并找出调用哪些方法.

Eclipse调用层次结构视图仅向我显示所有调用B.getCurrentA().

我怎样才能做到这一点?


编辑

克里斯海耶斯明白我想做什么.为了在不破坏整个系统的情况下重构一些非常糟糕的遗留代码,我需要首先使用Hibernate的投影微调一些查询(系统中的每个映射实体都被急切加载,并且许多实体是相关的,因此一些查询需要很长时间时间取出一切).但首先我需要找到使用哪些属性,以便我不会在某处获得NullPointerException ...

这是我手动做的一个例子:

    使用Eclipse的搜索查找对B.getCurrentA()的所有调用;

    打开找到的第一个方法,让我们说它是下面的方法:

    public class CController {
        C c = new C();
        CFacade facade = new CFacade();
        List Cs = new ArrayList();
    
        public void getAllCs() {
            c.setA(B.getCurrentA()); // found it!
            facade.search(c);
        }
    }
    

    在CFacade类中打开搜索方法:

    public class CFacade {
        CBusinessObject cBo = new CBusinessObject();
    
        public List search(C c) {
            // doing stuff...
            cBo.verifyA(c);
            cBo.search(c); // yes, the system is that complicated
        }
    }
    

    打开CBusinessObject类中的verifyA方法并标识使用的字段a2:

    public class CBusinessObject {
        public void verifyA(c) {
            if (Integer.valueOf(1).equals(c.getA().getA2())) {
                // do stuff
            else {
                // something else
            }
        }
    }
    

    接下来的216场比赛重复步骤2-4 ......耶.

请帮忙.

1 个回答
  • 如果要更改/重构任何源代码,则必须手动查找所有用法并应用代码更改;

    无论如何,我有两种不同的方法

      静态搜索你可以简单地Text Search在eclipse中找到它的出现getA2().它将直接带你到Caller方法(这里是CBusinessObject.verifyA()) - 但是它会给你每个getA2()的出现,可能来自不同的类

      运行时搜索用于java instrumentation API在运行时更改所需方法的字节代码以查找调用类并运行为java agent - 使您能够识别调用者而不触及现有代码库,并且非常有用,尤其是当您无法访问源代码时码.

    在这里,您将了解如何实施

    步骤1-编写代理主类以启动检测

    public class BasicAgent {
                    public static void premain(String agentArguments, Instrumentation instrumentation){
                        System.out.println("Simple Agent");
                        FindUsageTransformer transformer = new FindUsageTransformer ();
                        instrumentation.addTransformer(transformer,true);
                    }
                }
    

    第2步 - 编写ClassFileTransformer实现并捕获该方法

    public class FindUsageTransformer implements ClassFileTransformer{
    
            Class clazz = null;
            public byte[] transform(ClassLoader loader,String className,Class<?>  classBeingRedefined,  ProtectionDomain    protectionDomain,
                    byte[]              classfileBuffer)    throws IllegalClassFormatException {
                if(className.equals("A")){
                    doClass(className, classBeingRedefined, classfileBuffer);
                }
                return classfileBuffer;
            }
            private byte[] doClass(String name, Class clazz, byte[] b) {
                ClassPool pool = ClassPool.getDefault();
                CtClass cl = null;
                try {
                  cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
                  CtMethod method =  cl.getDeclaredMethod("getA2");
                  // here you have lot of options to explore
                  method.insertBefore("System.out.println(Thread.currentThread().getStackTrace()[0].getClassName()+ Thread.currentThread().getStackTrace()[0].getMethodName());");
                  b = cl.toBytecode();
                } catch (Exception e) {
                  System.err.println("Could not instrument  " + name
                      + ",  exception : " + e.getMessage());
                } finally {
                  if (cl != null) {
                    cl.detach();
                  }
                }
                return b;
              }
    

    步骤3-为代理类创建jar文件(你必须设置带有premain类的清单文件,并添加javaassit jar)给出构建文件的片段 - 你也可以手动完成

    <jar destfile="build/jar/BasicAgent.jar" basedir="build/classes">
                    <manifest>
                        <attribute name="Manifest-Version" value="1.0"/>
                        <attribute name="Premain-Class" value="com.sk.agent.basic.BasicAgent"/>
                        <attribute name="Boot-Class-Path" value="../lib/javassist.jar"/>
                    </manifest>
                </jar>
    

    步骤4-使用java代理运行主应用程序 - 在此之前将VM参数设置为加载代理

                -`javaagent:D:\softwares\AgentProject\AgentLib\build\jar\BasicAgent.jar`
    

    先决条件:您需要javassist.jar在课程路径中.

    2023-02-10 13:35 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有