2016-07-02 9 views
1

Я хочу распечатать вызовы методов Java с именами и значениями параметров и вернуть результаты.Является ли Antlr правильным инструментом для отслеживания вызовов методов Java с именами и значениями параметров и результата возврата?

Я не хочу вручную добавлять инструкции трассировки, особенно когда код находится в сторонней библиотеке. Мне нужно понять взаимодействие с библиотекой, особенно когда используются обратные вызовы.

Я попытался использовать обертку, но столкнулся с проблемами, поэтому подкласс лучше. (т. е. вызовы wrappedObject.methodA() или super.methodA())

Это боль, чтобы написать этот код, особенно когда есть много методов.

Я хочу, чтобы Java могла делать это автоматически, так как в нем есть все, чтобы сделать это возможным.

Каков наилучший способ для этого? Подстановка объектов с помощью оболочки или подкласса является компромиссом.

Итак, следующим шагом является добавление кода трассировки в оболочку или подкласс. Я думал написать парсер для генерации кода.

Я использовал yacc & lex before, и только что узнал о Antlr.

Является ли Antlr правильным инструментом для этого? Как мне это сделать? Раньше я не использовал Antlr, но видел его.

Спасибо.

Вот что я хочу сделать -

// 3rdParty library under investigation, with evolving versions 
import com.3rdParty.lib.Service; 
import com.3rdParty.lib.Callback; 

MyExistingClass { 

    Service service = new Service(); 

    // Need to understand 3rd party library service and callback interactions 
    // Also need to write my own callbacks using 3rd party interface 

    if (traceMethod1) { 
     service.doSomething(param1, new CallbackWrapper(), param3); 
    } 
    else if (traceMethod2) { 
     service.doSomething(param1, new CallbackSubclass(), param3); 
    } 
    else { 
     // Original code 
     // Service calls Callback methods 
     service.doSomething(param1, new Callback(), param3); 
    } 
} 

-------------------------------------------------------------------------------- 

// 3rd Party code - Service calls Callback methods 

package com.3rdParty.lib; 

public Callback extends SomeBaseClass { 

    public void methodA(int code, String action, SomeClass data) { 
     // do method A stuff 
    } 

    public String methodB(String name, boolean flag) { 
     // do method B stuff 
     return result; 
    } 

    ...etc. 
} 

-------------------------------------------------------------------------------- 

// Wrapper class - traceMethod1 

package com.my.package; 

import com.3rdParty.lib.Callback; 

public CallbackWrapper implements SomeCallbackInterface { 

    Callback cb = new Callback(); 

    public void methodA(int code, String action, SomeClass data) { 
     logger.debug("CallbackWrapper.methodA() called"); 
     logger.debug(" code = " + code); 
     logger.debug(" action = " + action); 
     logger.debug(" data = " + data); 

     cb.methodA(code, action, data); 

     logger.debug("CallbackWrapper.methodA() returns"); 
    } 

    public String methodB(String name, boolean flag) { 
     logger.debug("CallbackWrapper.methodB() called"); 
     logger.debug(" name = " + name); 
     logger.debug(" flag = " + flag); 

     String result = cb.methodB(name, flag); 

     logger.debug("CallbackWrapper.methodB() returns result = " + result); 

     return result; 
    } 

    ...etc. 
} 

-------------------------------------------------------------------------------- 

// Subclass - traceMethod2 

package com.my.package; 

import com.3rdParty.lib.Callback; 

public CallbackSubclass extends Callback { 

    public void methodA(int code, String action, SomeClass data) { 
     logger.debug("CallbackSubclass.methodA() called"); 
     logger.debug(" code = " + code); 
     logger.debug(" action = " + action); 
     logger.debug(" data = " + data); 

     super.methodA(code, action, data); 

     logger.debug("CallbackSubclass.methodA() returns"); 
    } 

    public String methodB(String name, boolean flag) { 
     logger.debug("CallbackSubclass.methodB() called"); 
     logger.debug(" name = " + name); 
     logger.debug(" flag = " + flag); 

     String result = super.methodB(name, flag); 

     logger.debug("CallbackSubclass.methodB() returns result = " + result); 

     return result; 
    } 

    ...etc. 
} 
+0

Я не совсем понимаю, что вы хотите сделать, но это больше похоже на работу для аспектно-ориентированного программирования (например, используйте [Spring AOP] (http://docs.spring.io/spring/docs/ current/spring-framework-reference/html/aop.html) или [AspectJ] (https://eclipse.org/aspectj/)), чем то, для чего вам нужен синтаксический анализатор. – Jesper

+0

Спасибо. Только что отредактировал оригинальный пост с примером кода, чтобы проиллюстрировать вопрос. – alteh

ответ

0

Самый простой способ сделать такую ​​вещь в Java, чтобы работать с байт-код, а не исходный код. Используя BCEL (https://commons.apache.org/proper/commons-bcel/) или ASM (http://asm.ow2.org/), вы можете динамически создавать и загружать измененные версии существующих классов или даже совершенно новые классы, созданные с нуля.

Это все еще не так просто, но это намного проще, чем пытаться сделать перевод исходного кода.

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

0

ANTLR - это неправильный инструмент. Хотя вы можете получить Java-грамматики для ANTLR, которые будут строить AST, ANTLR не поможет вам, многое, пытаться изменить AST или регенерировать компилируемый исходный текст.

Что вам нужно, это Program Transformation System (PTS). Это инструменты, которые анализируют исходный код, создают АСТ, предоставляют вам средства для модификации этих АСТ, как правило, с исходными преобразованиями источника, и могут регенерировать компилируемый исходный текст из измененного дерева.

Трансформации источник-источник для ВТС, как правило, написаны с точки зрения языка, чтобы быть трансформированных синтаксис (в данном случае, Java):

 if you see *this*, replace it by *that* if some *condition* 

Наш DMS Software Реинжиниринг Toolkit является такой PTS с доступным интерфейсом Java.

Что вы хотите сделать, это очень похоже на аппаратный код; просто измените методы жертвы, чтобы сделать их желаемой трассировкой. См. Branch Coverage Made Easy для примеров того, как мы реализовали инструмент инструментария для Java, используя такие перезаписываемые источники для источника.

В качестве альтернативы вы можете написать правила, которые реплицировали классы и методы-жертвы в качестве подклассов с помощью проводки, указанной в проводнике, как вы предложили. Инструментарий, вероятно, проще, чем копирование всего. [Конечно, когда вы пишете правила трансформации, вам действительно все равно, как меняется код, поскольку в вашем случае вы собираетесь выбросить его после того, как вы закончите с ним; вы заботитесь о том, как много нужно написать правила]

См. DMS Rewrite Rules для подробного обсуждения того, как выглядят такие правила, и отработанный пример правил перезаписи, которые вносят изменения в исходный код.

Другие предлагают сделать преобразование по скомпилированному байтовому коду. Да, это работает по той же причине, что и система PTS, но вы можете вручную взломать код, и преобразования, написанные как куча процедурного кода, работающего над инструкциями JVM, не читаются простым человеком. В отсутствие альтернативы я понимаю, что люди придерживаются такого подхода. Мой главный пункт : альтернативы.

 Смежные вопросы

  • Нет связанных вопросов^_^