Переписывание вызовов методов в скомпилированных классах Java

Я хочу заменить вызовы данного класса вызовами другого класса в теле метода при анализе файлов скомпилированного класса...
или, другими словами, существует ли метод определения использования данного класса в методе и замены только этой части метода с помощью чего-то вроде 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 ответов

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

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

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

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

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).

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

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

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

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

Другие вопросы по тегам