Подтвердить что ты не робот

Как я могу получить полную иерархию вызовов исходного кода Java?

Это немного сложно объяснить. У меня есть класс 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;
    }
}

Мне нужно найти все применения класса A , возвращаемого B. Итак, скажем, класс C вызывает c.setA(B.getCurrentA()), а затем далее там вызов c.getA().getA2();, я бы хотел найти все это.

В реальном сценарии у меня есть 217 разных классов, которые вызывают B.getCurrentA(). Я не могу вручную выполнить все вызовы в Eclipse и узнать, какие методы получаются.

В представлении иерархии вызовов Eclipse отображаются только все вызовы B.getCurrentA().

Как я могу это достичь?


ИЗМЕНИТЬ

Крис Хейс понял, что я хочу делать. Чтобы реорганизовать какой-то действительно плохой унаследованный код, не нарушая работу всей системы, мне нужно сначала настроить некоторые запросы с помощью прогнозов Hibernate (каждый сопоставленный объект в системе загружен, и многие объекты связаны друг с другом, поэтому некоторые запросы занимают LONG время извлечения всего). Но сначала мне нужно найти, какие свойства используются, чтобы я не получал исключение NullPointerException где-то...

Вот пример того, что мне нужно сделать вручную:

  • Используйте Eclipse Search, чтобы найти все вызовы B.getCurrentA();
  • Откройте первый найденный метод, скажем так:

    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);
        }
    }
    
  • Откройте метод поиска в классе 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
        }
    }
    
  • Откройте метод verifyA в классе CBusinessObject и определите, что используется поле a2:

    public class CBusinessObject {
        public void verifyA(c) {
            if (Integer.valueOf(1).equals(c.getA().getA2())) {
                // do stuff
            else {
                // something else
            }
        }
    }
    
  • Повторите шаги 2-4 для следующих 216 совпадений... Yay.

Пожалуйста, помогите.

4b9b3361

Ответ 1

Если вы хотите внести изменения/рефакторинг исходного кода, вам придется вручную найти все способы использования и применить изменения кода;

В любом случае у меня есть два разных aproach

  • Статический поиск   Вы можете просто сделать 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 в пути к классу.

Ответ 2

В зависимости от IDE вы используете эту проблему, проще найти.

Eclipse IDE имеет один из самых потенциальных существующих модулей иерархии вызовов, вам просто нужно поместить мышь в объявление метода, которое вы хотите найти и выполнить Ctrl + Alt + H Это даст вам всю иерархию того метода, который использует метод, который вы хотите проанализировать.

Также модуль иерархии вызовов предлагает режим, в котором вы можете найти методы, которые вызывает ваш метод.

Дополнительная информация: http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.cdt.doc.user%2Freference%2Fcdt_u_call_hierarchy_view.htm

Ответ 3

В IntelliJ IDEA, если вы хотите найти способы использования c.getA().getA2();, щелкните правой кнопкой мыши на A.a2 и выберите "find usages". Аналогично для A.a1 и B.getCurrentA(). Неиспользуемые поля и методы отображаются в другом формате в IDEA. Я слышал, что IntelliJ имеет больше возможностей рефакторинга, чем Eclipse, но я уверен, Eclipse делает то же самое, немного иначе.

Кроме того, используя grep, find и sed, вы можете искать соответствующие методы, только в файлах, которые находятся в том же пакете, что и A, или импортируют A, или записывают его по имени.

Ответ 4

Надеюсь, я правильно понял ваш вопрос. Я думаю, вы можете использовать функцию grep -Irns для поиска вызовов. Вы можете grep для getA().getA2(). Это вернет строки, из которых вызывается функция, а также номера строк.

Ответ 5

Вместо сканирования всех ссылок на метод getCurrentA выполните проверку всех ссылок на класс A.

Это покажет вам всюду, что этот класс используется в вашей программе, и вы, вероятно, обнаружите, что легче пройти и просмотреть этот список вручную и решить, нужно ли действовать по каждому найденному результату, чем пытаться сделать что-нибудь интересное.

Ответ 6

Самый простой способ найти использование вызовов - использовать ссылки в eclipse, но есть забавный способ

  • Измените имя метода на B.getCurrentAA()
  • Создайте свой проект
  • Ваш проект компилируется с ошибкой
  • Перейдите к разделу "Знаки" и просмотрите ошибку использования и найдите использование вашего метода.

Ответ 7

Я думаю, IntelliJ может решить вашу проблему. Он имеет функцию "Анализировать данные", и я думаю, что он делает то, что вы ищете:

Вот мой пример кода:

public class Main {

    private static A a = new A();  //nevermind the way it is initialized

    public static A getA(){
        return a;
    }

    public void method(){
        A myA = getA();
        Integer a1 = myA.getA1();  //this line is found
        Integer a2 = myA.getA2();  //this line is found
    }

    public void anotherMethod(){
        A myA = new A();         
        Integer a1 = myA.getA1();  //this line is NOT found
        Integer a2 = myA.getA2();  //this line is NOT found
    }
}

Запуск "Анализ потока данных отсюда" (с курсором на строке return a;):

enter image description here

Извините, что предоставил вам только решение с IntelliJ (протестировано с помощью IntelliJ-13 Ultimate Edition)