Ищете удобный способ вызова Java из C ++ - PullRequest
29 голосов
/ 24 сентября 2011

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

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

Так что в идеале я хотел бы написать код C ++, который может вызывать классы Java так же легко, как C ++ / 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 все в порядке. Я просто хочу приятного интерфейса к нему.

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

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

Существует ли такая бесплатная переносимая библиотека / инструмент с открытым исходным кодом или я сплю?

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

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

ВАЖНО

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

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

https://github.com/danielearwicker/cppjvm

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

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

Ответы [ 10 ]

16 голосов
/ 28 сентября 2011

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

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

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

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

7 голосов
/ 28 сентября 2011

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

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

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

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

4 голосов
/ 06 мая 2015

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

https://github.com/mo22/jnipp

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

2 голосов
/ 26 сентября 2011

Повторный вызов Java из C ++.

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

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

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

...

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

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

...

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

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

НТН

1 голос
/ 27 сентября 2011

Как насчет использования Thrift или буферных протоколов для упрощения вызовов Java на C ++?

1 голос
/ 27 сентября 2011

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

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

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

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

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

1 голос
/ 24 сентября 2011

Статья Java. Совет 17: Интеграция Java с C ++ подробно описывает, как это сделать.

0 голосов
/ 28 сентября 2011

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

http://java4cpp.kapott.org/

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

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

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

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

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

0 голосов
/ 27 сентября 2011

Поскольку CORBA, кажется, не то, что вам нужно, вот ссылки, описывающие, как запускать JVM из C / C ++ и вызывать JAVA-методы.

http://java.sun.com/docs/books/jni/html/invoke.html и http://java.sys -con.com / node / 45840

PS: при взаимодействии Java с C ++ вы также должны взглянуть на JNA или bridj .

0 голосов
/ 27 сентября 2011

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

...