Javassist добавить метод и вызвать
Я застрял с javassist. Я добавил новый метод в свой класс object во время выполнения.
мой класс объекта:
package tmp3;
public class Car {
public Car(){}
}
мой тестовый класс:
package tmp3;
import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
public class TestMain {
public static void main(String[] args) {
try {
CtClass ctclass = ClassPool.getDefault().get("tmp3.Car");
CtMethod newmethod = CtNewMethod.make("public void testPrint() { System.out.println("test ok"); }",ctclass);
ctclass.addMethod(newmethod);
ctclass.writeFile();
for(Method me: ctclass.toClass().getDeclaredMethods()){ //test print, ok
System.out.println(me.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
но после этого момента, я не знаю, как назвать(вызвать) его. Я читал, что javassist не имеет возможности вызывать методы. Тогда как я могу вызвать метод, который я добавил с javassist?
Я пробовал много вещей за два дня, но не имел успеха. Не могли бы вы помочь мне с это?
2 ответов
классы Java имеют статические интерфейсы, что означает, как вы, вероятно, уже знаете, Java не предназначен по умолчанию для добавления методов в класс во время выполнения, поэтому это немного сложно, но не так сложно достичь того, что вы хотите.
вы использовали Javassist, структуру модификатора байт-кода, чтобы сконструировать скомпилированный класс для добавления большего байт-кода, представляющего новый метод. Вы можете иметь один из двух сценариев:
Сценарий 1: код, который компилируется вместе с вашим автомобилем класс перед инъекцией
в этом случае, когда ваш код компилируется, компилятор Java знает только Car
интерфейс без каких-либо инъекций. Так ты не могу просто вызовите введенный метод напрямую, например:
Car car = new Car();
car.testPrint();
вы должны сделать это путем отражения, как @Scorpion правильно прокомментировал:
Car car = new Car();
Method method = car.getClass().getMethod("testPrint", new Class[]{});
method.invoke(car,new Object[]{});
но это не единственный способ...
Сценарий 2: код, который использует ваш скомпилированный и введенный Класс!--15-->
если вы скомпилировали Car
класс, впрысните его и после написать код против скомпилированного класса (например, имея Car
class в файле jar) вы сможете вызвать свой введенный метод, как если бы это был любой другой обычный метод.
выполнить следующее упражнение:
- компилировать
Car
класс - запустите TestMain, который будет делать инъекцию
- создать другой проект в IDE и добавьте в путь к классам этого проекта каталог с введенным классом или создайте банку только с введенным классом и добавьте эту банку в classpath
- создайте класс в новом проекте, который создает новый
Car
экземпляр, обратите внимание, что теперь вы можете вызвать метод testPrint без каких-либо проблем.
несколько вещей, которые вы должны держать внимание:
- если ты перезаписи исходного класса с вводят class, вы можете получить недопустимый класс, в результате чего
java.lang.ClassFormatError
С сообщением об ошибке, говорящее, что у вас есть усеченный файл класса. Это происходит, если Javassist не загрузил весь байт-код в память и попытался записать и прочитать в тот же файл класса и из него, что приводит к полному беспорядку. Чтобы избежать этого, вы можете либо написать другой путь, либо загрузить весь байт-код в память перед записью файла (используйтеtoByteCode()
СCtClass
) . - если у вас есть два файлы классов, один с введенным кодом и один с исходным кодом, не забудьте есть только один в вашем classpath.
используйте отражение java для вызова его, javassist для модификации и загрузки класса ... затем Java reflection для его запуска (invoke ...).