Реинициализация Java-класса - PullRequest
1 голос
/ 15 марта 2011

Мы работаем над Java-агентом JVMTI, который используется для обработки файлов классов Java. Небольшая его часть (очевидно) является собственным кодом C ++, но большей частью является код Java, который загружается по сети и вызывается из собственного кода агента. Мы используем инструмент покрытия кода для сбора тестового покрытия для части Java, которая выполняет инструментарий исходного кода.

Теперь, когда наш агент запускается, некоторые классы инициализируются, в частности, java.lang.ref.Reference, который запускает Thread. Наш агент использует метод запуска потока с пользовательским Java-кодом, который оснащается инструментом покрытия кода. Инструмент покрытия помещает некоторые статические внутренние классы со статическими инициализаторами в наш код агента java, поэтому он выполняется в результате инициализации java.lang.ref.Reference.

Проблема в том, что в настоящее время (когда инициализируется java.lang.ref.Reference), некоторые базовые функциональные возможности JVM еще не созданы. В частности, инициализатор инструментов покрытия кода хочет получить доступ к System.getProperty (String name), но System.props по-прежнему равен нулю, поэтому в результате вызова возникает исключение NullPointerException. Это приводит к тому, что статический внутренний класс инструмента покрытия кода остается неинициализированным, класс находится в состоянии initialization_error, результатом является NoClassDefFoundError. Каждый последующий доступ к этому классу приводит к NoClassDefFoundError.

Мое намерение теперь состоит в том, чтобы проигнорировать эту первоначальную ошибку инициализации и подождать до VM_Start, а затем сбросить ClassState рассматриваемого класса в «связанный». Таким образом, я надеюсь, что JVM попытается снова инициализировать класс при последующих обращениях к классу.

У кого-нибудь есть идея, если это можно сделать из агента JVMTI, и дайте мне несколько советов, как это можно сделать?

Ответы [ 2 ]

0 голосов
/ 15 марта 2011

RetransformClasses после VM_Start сгенерирует перехват загрузки нового класса для Reference, позволяя вам выполнять инструментирование в безопасной фазе VM ... Либо просто Retransform Reference, либо getLoadedClasses и Retransform их все.

0 голосов
/ 15 марта 2011

Из вашего описания я чувствую, что ваш код слишком тесно связан. Что вы действительно хотите, так это иметь инициализированную Java VM до того, как вы начнете свои тесты.

Поэтому вместо того, чтобы связываться с собственным кодом и агентом, я предлагаю разделить код на три класса:

  • Java-код в абстрактном базовом классе
  • Класс, расширяющий базовый класс и реализующий абстрактные методы с собственным кодом C ++. В идеале этот класс не должен содержать никакого кода Java, кроме объявлений собственных методов.
  • Класс макета для тестов, который определяет те же методы с пустыми телами (или те, которые просто возвращают null).

Для тестов создайте экземпляр класса макета. Переопределите методы, которые вам нужны для теста, чтобы вы могли возвращать имитируемые объекты данных, которые нужны тестируемому коду (см. mockito для примера тестирования макета)

Либо протестируйте загрузочный код Java в тестовом примере. Во всех остальных тестах добавьте класс в ваш путь к классам и просто создайте его экземпляр как обычно.

...