Переписывание вызовов методов в скомпилированных классах Java - PullRequest
4 голосов
/ 11 августа 2009

Я хочу заменить вызовы данного класса вызовами другого класса в теле метода при анализе файлов скомпилированного класса ...
или, другими словами, существует ли метод определения использования данного класса в методе и замены только этой части метода, используя что-то вроде javaassist .

например .. если бы у меня была скомпилированная версия

class A { public int m() { int i = 2; B.multiply(i,i); return i; } }

существует ли способ обнаружения использования B и последующего изменения кода для выполнения

class A { public int m() { int i = 2; C.divide(i,i); return i; } }

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

Есть мысли?

Ответы [ 5 ]

3 голосов
/ 11 августа 2009

Как говорит @djna, можно изменить файлы байт-кода перед их загрузкой, но вы, вероятно, не хотите этого делать:

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

Переписывание байт-кода полезно в некоторых случаях. Например, реализации JDO используют переписывание байт-кода для замены выборок членов объекта вызовами в постоянные библиотеки. Однако если у вас есть доступ к исходному коду для этих файлов, вы получите лучшее (то есть более удобное в обслуживании) решение, предварительно обработав (или сгенерировав) исходный код.

РЕДАКТИРОВАТЬ: и AOP или Groovy тоже звучат как жизнеспособные альтернативы, в зависимости от степени переписывания, которую вы ожидаете сделать.

2 голосов
/ 11 августа 2009

BCEL или ASM .

Недавно я посмотрел несколько библиотек для чтения файлов классов Java. BCEL был самым быстрым, имел наименьшее количество зависимостей, компилировался из коробки и имел восхитительно простой API. Я предпочел BCEL, а не ASM, потому что ASM имеет больше зависимостей (хотя API по общему мнению проще).

AspectJ, как упоминалось ранее, является еще одним жизнеспособным вариантом.

BCEL действительно прост. Вы можете получить список методов в трех строках кода:

ClassParser cp = new ClassParser( "A.class" );
JavaClass jc = cp.parse();
Method[] m = jc.getMethods();

Существуют и другие возможности API для дальнейшего самоанализа, включая, как мне кажется, способы получения инструкций в методе. Однако это решение, вероятно, будет более трудоемким, чем AspectJ.

Другая возможность состоит в том, чтобы изменить сами методы умножения или деления, а не пытаться изменить все экземпляры кода, который вызывает операцию. Это было бы легче сделать с BCEL (или ASM).

1 голос
/ 11 августа 2009

Если вы не возражаете против использования Groovy, вы можете перехватить вызов на B.multiply и заменить его на C.divide. Вы можете найти пример здесь .

1 голос
/ 11 августа 2009

Указан формат байт-кода для скомпилированной Java и существуют продукты, которые им манипулируют.

Эта библиотека обладает необходимыми возможностями. Я понятия не имею, насколько легко выполнить эти преобразования надежно.

0 голосов
/ 11 августа 2009

Гораздо проще выполнить эти операции заранее, когда исполняемый файл на диске изменяется перед запуском приложения. Манипулирование кодом в памяти во время выполнения даже более подвержено ошибкам, чем манипулирование кодом в памяти в C / C ++. Зачем вам это нужно?

...