Подтвердить что ты не робот

Поиск удобного способа вызова Java из С++

Кажется, что большинство документации или вспомогательных библиотек, связанных с JNI (Java Native Interface), связаны с вызовом собственного кода с Java. Это, по-видимому, основное его использование, даже если оно способно больше.

Я хочу в основном работать в обратном направлении: изменить существующую (довольно большую) переносимую С++-программу, добавив к ней некоторые библиотеки Java. Например, я хочу, чтобы он вызывал базы данных через JDBC или системы очереди сообщений через JMS или отправлял электронные письма или вызывал мои собственные классы Java и т.д. Но с необработанным JNI это довольно неприятно и подвержено ошибкам.

Поэтому я бы идеально хотел написать С++-код, который может вызывать классы Java так же легко, как С++/CLI может вызывать классы CLR. Что-то вроде:

using namespace java::util::regex; // namespaces mapped

Pattern p = Pattern.compile("[,\\s]+");

array<java::lang::String> result = 
    p.split("one,two, three   four ,  five");

for (int i=0; i < result.length(); i++)
    std::cout << result[i] << std::endl;

Таким образом, мне бы не пришлось вручную выполнять работу по получению идентификатора метода путем передачи имени и странных строк подписи, и будет защищен от ошибок программирования, вызванных непроверенными API-интерфейсами для вызова методов. На самом деле это будет похоже на эквивалентную Java.

NB. Я ЕСМЬ ЕЩЕ РАЗГОВОР О ИСПОЛЬЗОВАНИИ JNI! В качестве базовой технологии она идеально подходит для моих нужд. Он "в процессе" и очень эффективен. Я не хочу запускать Java в отдельный процесс и делать RPC-вызовы. Сам JNI в порядке. Мне просто нужен приятный интерфейс.

Для создания эквивалентных классов С++, пространств имен, методов и т.д. должен быть создан инструмент генерации кода, чтобы точно соответствовать тому, что отображается набором классов Java, которые я указываю. Сгенерированные классы С++:

  • Имейте функции-члены, которые принимают аналогично завернутые версии своих параметров, а затем делают необходимые JUDI Voodoo для выполнения вызова.
  • Оберните возвращаемые значения таким же образом, чтобы я мог цеплять вызовы естественным образом.
  • Поддерживать статический кеш для каждого класса идентификаторов методов, чтобы каждый раз просматривать их.
  • Будьте полностью потокобезопасными, портативными, с открытым исходным кодом.
  • Автоматически проверять исключения после каждого вызова метода и вызывать исключение std С++.
  • Также работайте, когда я пишу собственные методы в обычном порядке JNI, но мне нужно вызвать другой код Java.
  • Массив должен работать полностью последовательно между примитивными типами и классами.
  • без сомнения, нужно что-то вроде глобального обернуть ссылки, когда они должны выжить вне локальной системы отсчета - опять же, должны работать одинаково для всех ссылок массива/объекта.

Есть ли такая бесплатная, открытая исходная портативная библиотека/инструмент или мне снится?

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

Обновление: комментарий о SWIG привел меня к этому предыдущему вопросу, что, по-видимому, указывает на то, что речь идет в основном о противоположном направлении и поэтому я не буду делать то, что хочу.

ВАЖНО

  • Это о возможности написания кода на С++, который управляет классами Java и объектами, а не наоборот (см. заголовок!)
  • Я уже знаю, что JNI существует (см. вопрос!). Но рукописный код API JNI излишне подробен, повторяется, подвержен ошибкам, а не проверяется типом во время компиляции и т.д. Если вы хотите использовать метод кэширования Идентификаторы и объекты класса еще более подробные. Я хочу автоматически генерировать классы оболочки С++, которые заботятся обо всем этом для меня.

Обновление: Я начал работать над своим собственным решением:

https://github.com/danielearwicker/cppjvm

Если это уже существует, дайте мне знать!

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

4b9b3361

Ответ 1

Да, существуют существующие инструменты, которые делают именно это - создайте обертки С++ для классов Java. Это делает использование Java API на С++ более прозрачным и приятным, с более низкой стоимостью и риском.

Тот, который я использовал больше всего, JunС++ ion. Он зрелый, мощный и стабильный. Основной автор очень хорош и очень отзывчив. К сожалению, это коммерческий продукт и дорогой.

Jace - бесплатный инструмент с открытым исходным кодом с лицензией BSD. Прошли годы с тех пор, как я в последний раз играл с Джейсом. Похоже, там еще какое-то активное развитие. (Я все еще помню пост USENET оригинальным автором, более десяти лет назад, задавая в основном тот же вопрос, который вы задаете.)

Если вам нужно поддерживать обратные вызовы с Java на С++, полезно определить классы С++, реализующие интерфейсы Java. По крайней мере, JunС++ ion позволяет передавать такие классы С++ методам Java, которые принимают обратные вызовы. В последний раз, когда я пробовал jace, это не поддержало это, но это было семь лет назад.

Ответ 2

Я один из главных архитекторов для продуктов интеграции языка Codemesh, включая ион JunС++. Мы делаем такую ​​интеграцию с 1999 года, и она работает очень хорошо. Самая большая проблема не в части JNI. JNI утомительно и сложно отлаживать, но как только вы это исправите, он в основном просто работает. Время от времени вы подвергаетесь сбоям от JVM или обновления ОС, а затем вам нужно точно настроить ваш продукт, но в целом он стабильный.

Самая большая проблема - это сопоставление типов типов и компромиссы между общим удобством использования и целевым решением. Например, вы заявляете, что вам не нравится тот факт, что JACE рассматривает все ссылки на объекты как глобальные. Мы делаем то же самое (с некоторыми выходными люками), потому что выясняется, что это поведение, которое лучше всего подходит для 95% клиентов, даже если это вредит производительности. Если вы собираетесь публиковать API или продукт, вы должны выбрать настройки по умолчанию, которые делают работу большинством людей. Выбор локальных ссылок в качестве параметра по умолчанию был бы неправильным, потому что все больше людей пишут многопоточные приложения, и многие API-интерфейсы Java, которые люди хотят использовать с других языков, по сути, многопоточны с асинхронными обратными вызовами и т.п.

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

Удачи вам в вашем проекте. Это большая работа, чтобы получить право. Мы потратили на это несколько лет, и мы все еще делаем это лучше.

Ответ 3

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

https://github.com/mo22/jnipp

Он имеет небольшой промежуток времени выполнения (< 30kb), управляет ссылками и поддерживает создание интерфейсов класса Java. То есть LocalRef > stringArray; а затем с помощью stringArray [1] → getBytes() или что-то в этом роде.

Ответ 4

Вызов Java из С++.

Вы можете делать то, что хотите, но вы должны позволить Java контролировать. Что я имею в виду, так это то, что вы создаете потоки Java, которые вызывают в Native code, и оттуда они блокируются, ожидая, когда ваш собственный код даст ему что-то делать. Вы создаете столько потоков Java, сколько вам нужно, чтобы получить достаточную рабочую работу/работу.

Итак, ваше приложение С++ запускается, оно создает JVM/JavaVM (согласно документированному способу, например, в кодовой базе qtjambi, см. ниже), это, в свою очередь, выполняет обычную инициализацию JNI и System.loadLibrary() и предоставляет JAR с "родная" связь. Затем вы инициализируете кучу потоков и вызываете некоторый код JNI (который вы создали), где они могут заблокировать ваш код на С++, чтобы дать им некоторую работу.

Ваш код на С++ (предположительно из другого потока) затем устанавливает и передает всю информацию, необходимую одному из заблокированных и ожидающих работников Java-Thread, после чего ему предоставляется заказ для запуска, затем он может вернуться в pure-Java код для выполнения работы и возврата с результатом.

...

Можно создать и создать и содержать экземпляр JavaVM из кода С++. Это может привести к принудительной подаче собственных CLASSPATH/JAR для настройки среды, в которой вы должны инкапсулироваться внутри вашей программы на С++.

Очерк этого, как я уверен, вы уже нашли в http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

...

В проекте QtJambi (который я работаю и поддерживаю) существует своего рода генератор Java JNI С++ = > Java. Это довольно навязывается для инструментария Qt, но по существу он переводит кучу файлов заголовков С++ в коллекцию файлов C.cpp/.h и файлов *.hava С++, чтобы обеспечить связь и оболочку оболочки таким образом, чтобы схемы распределения конкурирующей памяти хорошо играйте вместе. Может быть, от этого что-то есть.

Это, безусловно, является доказательством того, что вы просите, чтобы генератор просто содержался в проекте qtjambi (но может быть независимым от некоторой работы), и это лицензия LGPL (open-source). Инструментарий Qt не является небольшим API, но он может генерировать 100 классов для покрытия высокого процента API ( > 85% и почти 100% частей Core/GUI).

НТН

Ответ 6

У меня также было много трудностей получение JNI для работы на разных операционных систем, справляясь с 32/64-разрядными архитектурами и следя за тем, чтобы были найдены и загружены правильные разделяемые библиотеки. Я нашел CORBA (MICO и JacorB) трудным в использовании.

Я не нашел эффективного способа позвонить из C/С++ в Java, и мои предпочтительные решения в этой ситуации должны запускать мой Java-код как:

  • отдельная программа что я могу легко запускать из программ C/С++ с java -cp myjar.jar org.foo.MyClass. Думаю, это слишком упростительно для вашей ситуации.

  • Как мини-сервер, принимающий запросы от C/С++ программ в гнезде TCP/IP и возвращая результаты через этот сокет. Это требует написания сетей и функций сериализации но отделяет процессы C/С++ и Java, и вы можете четко идентифицировать любые проблемы как находящиеся на стороне С++ или Java.

  • Как сервлет в Tomcat и сделайте HTTP-запросы от моего C/С++ программа (также будут работать и другие контейнеры сервлетов). Это также требует написания сетей и функций сериализации. Это больше похоже на SOA.

Ответ 8

Может быть, слишком большой молот для этого гвоздя, но не это то, что CORBA была построена для?

Ответ 10

Отвечая на мой собственный вопрос:

http://java4cpp.kapott.org/

Не является активным проектом. Автор рекомендует не использовать его с JDK 1.5 или новее.

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

java::lang::Integer* i = new java::lang::Integer("10");

delete i; // don't forget to do this!

Это также вызывает более тонкую проблему, чтобы представить совместимость присваивания (например, класс как подтип интерфейса, который он реализует) обертки должны наследовать друг от друга.