Загрузить класс OSGi из JNI

Я вызываю некоторый код C++, который пытается загрузить класс Java, например.

JNIEnv *jenv = ...
jclass cls = jenv->FindClass("org/some/bundle/SomeClass");

Теперь проблема в том, что этот класс находится в пакете OSGi, и приведенный выше код не может найти мой класс.

Эта проблема возникает только при выполнении модульных тестов (безголовые тесты Tycho-surefire). Есть ли простой способ заставить платформу OSGi найти мой класс из JNI? Что касается Java, я подозреваю, что что-то вроде Dynamic-ImportPackage могло решить мою проблему. Я не хочу менять стороннюю библиотеку C++ только для того, чтобы заставить ее работать с тестовой средой, поэтому я предпочитаю решение на стороне установки/конфигурации теста Java, если это возможно.


person Krumelur    schedule 07.06.2013    source источник


Ответы (2)


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

В общем, при загрузке класса вам нужно указать не только имя класса, но и загрузчик классов, который должен его загрузить. Это неизбежное требование модульности. Таким образом, ваш код должен иметь возможность найти пакет, который, как вы ожидаете, будет содержать класс, а затем вызвать его метод loadClass. Вы можете сделать это непосредственно в коде C++, но может быть проще написать служебный метод Java, чтобы сделать это, а затем просто вызвать этот метод из C++.

person Neil Bartlett    schedule 07.06.2013
comment
Я понимаю, и это подтверждает мое предположение. Вопрос в том, могу ли я как-то обойти это простой реконфигурацией, не меняя библиотеку С++ (над которой у меня нет прямого контроля)? - person Krumelur; 07.06.2013
comment
Например, я пробовал установить org.osgi.framework.system.packages.extra в бандл класса, загружаемого кодом C++, но это не помогло. - person Krumelur; 07.06.2013
comment
Не совсем. Как я уже сказал, JNIEnv считывает глобальный путь к классам приложения. Можно сделать классы пути к классам видимыми в пакетах OSGi, экспортировав их из системного пакета... это то, что достигается параметром org.osgi.framework.system.packages.extra. Но вам нужно пойти в другом направлении: импортировать из пакета OSGi в системный пакет, что невозможно. Единственный способ, который я могу придумать, - это переместить класс в глобальный путь к классам и экспортировать его оттуда. - person Neil Bartlett; 07.06.2013
comment
Спасибо. То, что вы пишете, имеет общий смысл. В настоящее время я не могу этого сделать (требует некоторого размышления и рефакторинга), но я считаю, что мог бы сделать эту работу, используя ваше предложение. Боль поддержки устаревшего кода в среде Eclipse/RCP :) - person Krumelur; 08.06.2013

Ну, я не уверен на 100%, что ваш случай похож на мой.

В моем RCP я получал исключение:

ClassNotFoundException: com.tool.packageA.IWantToLoadThisClass не может быть найден с помощью com.tool.packageB_1.0.0.qualifier


Простое решение заключалось в следующем:

  • Добавьте com.tool.packageA в com.tool.packageB MANIFEST.MF Require-Bundle.

Я хотел избежать этого решения, потому что я мог загружать другие классы, найденные в других пакетах, как обычно com.tool.packageC, com.tool.packageD (это не было сделано мной, поэтому я не знал, как это работает).


Поискав вокруг, я нашел другое решение, которое я в итоге использовал, чтобы сохранить вещи, похожие на текущие рабочие пакеты (com.tool.packageC, com.tool.packageD).

Решение было:

Вот как заставить его работать:

  1. Добавьте Eclipse-BuddyPolicy: registered в com.tool.packageB MANIFEST.MF
  2. Добавьте Eclipse-RegisterBuddy: com.tool.packageB в com.tool.packageA MANIFEST.MF
  3. Добавьте Require-Bundle: com.tool.packageB в com.tool.packageA MANIFEST.MF

Теперь com.tool.packageA.IWantToLoadThisClass будет виден из com.tool.packageB, и вы сможете найти его, когда jenv->FindClass("com/tool/packageA/IWantToLoadThisClass");.

Надеюсь, это поможет.

person Ayman Salah    schedule 26.02.2019