Java: получение байт-кода класса во время выполнения из одного JVM

Связано с: Есть ли способ получить байт-код для класса во время выполнения?

Я добавляю долговечность к Clojure, и я, наконец, готов к тому, чтобы добавить функции. В Clojure функции байт компилируются в классы с помощью методов invoke (среди прочих). Таким образом, функции являются первоклассными. Чтобы сделать эти прочные, мне нужно сериализовать и десериализовать эти классы. Как получить байт-код для класса без доступа к файлу .class?

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

Недостаточно использовать Serializable для установки и получения объекта Class. При десериализации мне нужно загрузить класс, а после последующих экземпляров VM может возникнуть конфликт имен классов. Мне нужно изменить байт-код, чтобы переименовать класс в нечто уникальное при десериализации/времени загрузки класса.

Ответ 1

Вы можете написать свой собственный ClassLoader и взломать схему, которая записывает байт-код при загрузке классов.

Вам нужно будет переопределить findClass, чтобы найти файл класса самостоятельно, загрузить его в память, сохранить данные где-нибудь (для последующей сериализации), а затем вызвать defineClass, чтобы определить этот класс в JVM.

Ответ 2

Если вы не запускаете код через сложный загрузчик классов, вы должны сделать что-то вроде этого:

Class<?> clazz = ....
String className = clazz.getCanonicalName();  // e.g. "foo.Bar"
String resourceName = ... // map className to a resource name; e.g. "/foo/Bar.class" 
InputStream is = clazz.getClassLoader.getResourceAsStream(resourceName);

Это дает вам описание содержимого файла ".class"... если оно может быть найдено.

предостережений. Некоторые загрузчики классов могут:

  • не позволяет открывать ресурсы ".class" вообще,
  • предоставит вам зашифрованный поток байт-кода или
  • предоставляют вам байт-коды, которые не являются точно тем, что выполняется, из-за некоторого "на лету" преобразования, выполняемого загрузчиком классов.

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

Ответ 3

Для этого также можно использовать Java Instrumentation API. Вы получаете доступ к байтам файла классов перед вызовом defineClass. Вы также можете изменить их!