#java #reflection #bytecode
#java #отражение #байт-код
Вопрос:
У меня есть следующее странное требование.
Мне дано:
- Список некоторых имен методов.
- Имена и типы параметров вышеуказанных методов.
- Функциональность вышеуказанных методов. Это выглядит следующим образом: для каждого параметра метод преобразует его в строку с использованием
toString
и получает массив строк. К этому массиву метод применяет функциюfoo
. Функцияfoo
принимает в качестве входныхString []
данных тип и выводитString
. Методы возвращают то, чтоfoo
возвращает.foo
код задается внутри объекта Java и доступен как черный ящик.
Информация в 1. и 2. может быть в текстовом или XML-файле. Для этой цели мы можем считать, что он доступен внутри объекта Java любым выбранным нами способом.
Задача состоит в том, чтобы создать .class
файл (т.Е. байт-код), который реализует эти методы и может быть запущен в JVM.
Я думаю, что эта библиотека ассемблера была бы одним из способов сделать это. Кто-нибудь может предложить более простой способ?
[РЕДАКТИРОВАТЬ:] Я могу придумать еще один способ: сначала сгенерировать .java
файл, а затем скомпилировать его, чтобы получить .class
файл.
[Контекст:] Я должен сделать это для нескольких сотен методов. Мне нужен ярлык, чтобы я мог автоматизировать свою работу, а не вручную писать код.
Комментарии:
1. Не могли бы вы дать больше контекста, чего вы хотите достичь… Единственная причина, по которой я вижу «создание» конкретных методов для общего поведения (foo), — это безопасность типов, которая полезна во время компиляции… Как вы собираетесь использовать / вызывать сгенерированный код?
2. Я не буду вызывать сгенерированный код. Что я хочу сделать, так это создать библиотеку API (jar) для использования кем-либо. Класс будет иметь определенное имя, поэтому они будут знать, какой API вызывать.
3. Хорошо, я вижу проблему с сотнями методов, будет ли список методов часто меняться или нет? можем ли мы привести пример используемого вами ввода?
4. @pgras: Я скоро приведу пример файла.
5. @pgras: он может меняться не часто, но время от времени он обязательно будет меняться, и этого достаточно, чтобы вызвать головную боль при синхронизации двух файлов, если я их закодирую вручную. [Редактировать: файл данных для чтения генерируется автоматическим способом, который считывает методы и выводит их типы, поэтому имеет смысл сделать обратное также автоматическим способом]
Ответ №1:
Вы могли бы сгенерировать необходимый программный код в синтаксисе Java и превратить его в файл класса с помощью компилятора. Можно создать экземпляр javac
во время выполнения и передать ему массив байтов вместо местоположения исходного файла. Это, вероятно, самый простой способ поддержки для других программистов.
Если вы хотите генерировать байт-код напрямую, наиболее часто используемой библиотекой является asm.
Комментарии:
1. Я думаю, что это, вероятно, было бы наиболее удобным способом (создание
.java
файла).2. Можете ли вы дать некоторую информацию о том, как это сделать
javac
, предположив, что я создал файл .java?3. Это в
javax.tools
пакете. В этой статье приведен пример: ibm.com/developerworks/java/library/j-jcomp/index.html . Я должен признать, что я сам не использовалjavax.tools
API.
Ответ №2:
Вот список библиотек байт-кода с открытым исходным кодом: http://java-source.net/open-source/bytecode-libraries
Взгляните на Javassist.
Ответ №3:
Я видел, как вы ответили на мой комментарий, но мне все еще не ясно, почему вы хотите сгенерировать код, который затем будет упакован в jar, просто введите его 🙂
Теперь, если вам нужен типобезопасный API со всеми методами, имеющими одинаковое поведение, вы могли бы предоставить динамический прокси для данного интерфейса (это оставляет вас с вопросом о том, как сгенерировать интерфейс 🙂
Вот пример, в котором все вызовы всех методов MyInterface будут обрабатываться методом invoke (просто добавьте методы в интерфейс, чтобы протестировать его)…
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
interface MyInterface {
String methodOne(String s);
String methodTwo(String s, Integer i);
}
static MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class }, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
StringBuilder result = new StringBuilder();
for (Object arg : args) {
result.append(arg.toString());
}
return result.toString();
}
});
public static void main(String[] args) {
System.out.println(proxy.methodOne("hello"));
System.out.println(proxy.methodTwo("world", 5));
}
}
Комментарии:
1. Если бы я мог так много печатать, не было бы необходимости задавать вопрос :-). Я использую Scala в первую очередь потому, что мне не нравится печатать.