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

Tar*_*rek 13 java eclipse hierarchy

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

public class A {
    private Integer a1;
    private Integer a2;
    // getters and setters.
}
Run Code Online (Sandbox Code Playgroud)

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

public static class B {
    public static A getCurrentA() {
        return a;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

我怎样才能做到这一点?


编辑

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

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

  1. 使用Eclipse的搜索查找对B.getCurrentA()的所有调用;
  2. 打开找到的第一个方法,让我们说它是下面的方法:

    public class CController {
        C c = new C();
        CFacade facade = new CFacade();
        List<C> Cs = new ArrayList<C>();
    
        public void getAllCs() {
            c.setA(B.getCurrentA()); // found it!
            facade.search(c);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在CFacade类中打开搜索方法:

    public class CFacade {
        CBusinessObject cBo = new CBusinessObject();
    
        public List<C> search(C c) {
            // doing stuff...
            cBo.verifyA(c);
            cBo.search(c); // yes, the system is that complicated
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 打开CBusinessObject类中的verifyA方法并标识使用的字段a2:

    public class CBusinessObject {
        public void verifyA(c) {
            if (Integer.valueOf(1).equals(c.getA().getA2())) {
                // do stuff
            else {
                // something else
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 接下来的216场比赛重复步骤2-4 ......耶.

请帮忙.

Sat*_*eri 12

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

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

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

  2. 运行时搜索用于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);
                }
            }
Run Code Online (Sandbox Code Playgroud)

第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;
          }
Run Code Online (Sandbox Code Playgroud)

步骤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>
Run Code Online (Sandbox Code Playgroud)

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

            -`javaagent:D:\softwares\AgentProject\AgentLib\build\jar\BasicAgent.jar`
Run Code Online (Sandbox Code Playgroud)

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