Как сгенерировать байт-код и сохранить в файл .class?

#java #reflection #bytecode

#java #отражение #байт-код

Вопрос:

У меня есть следующее странное требование.

Мне дано:

  1. Список некоторых имен методов.
  2. Имена и типы параметров вышеуказанных методов.
  3. Функциональность вышеуказанных методов. Это выглядит следующим образом: для каждого параметра метод преобразует его в строку с использованием 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 в первую очередь потому, что мне не нравится печатать.