Buscando una forma conveniente de llamar a Java desde C++


Parece que la mayoría de la documentación o bibliotecas auxiliares relacionadas con JNI (Java Native Interface) se refieren a llamar código nativo desde Java. Este parece ser el uso principal de la misma, a pesar de que es capaz de más.

Quiero trabajar principalmente en la dirección opuesta: modificar un programa portable C++ existente (bastante grande) agregando algunas bibliotecas Java a él. Por ejemplo, quiero hacer que llame a bases de datos a través de JDBC, o sistemas de cola de mensajes a través de JMS, o enviar correos electrónicos, o llamar a mi propio Java clases, etc. Pero con raw JNI esto es bastante desagradable y propenso a errores.

Así que idealmente me gustaría escribir código C++ que pueda llamar a clases Java tan fácilmente como C++/CLI puede llamar a clases CLR. Algo como:

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;

De esta manera, no tendría que hacer manualmente el trabajo de obtener el ID del método pasando el nombre y las extrañas cadenas de firma, y estaría protegido de los errores de programación causados por las API no verificadas para llamar a los métodos. De hecho, se vería mucho como el equivalente Java.

NB. ¡TODAVÍA ESTOY HABLANDO DE USAR JNI! Como tecnología subyacente, es perfecta para mis necesidades. Está" en proceso " y es altamente eficiente. No quiero ejecutar Java en un proceso separado y hacer llamadas RPC a él. El propio JNI está bien. Solo quiero una interfaz agradable.

Tendría que haber una herramienta de generación de código para crear clases C++ equivalentes, espacios de nombres, métodos, etc. para que coincida exactamente con lo que está expuesto por un conjunto de clases de Java que especifique. Las clases C++ generadas serían:

  • Tienen funciones miembro que aceptan versiones similares de sus parámetros y luego hacen el vudú JNI necesario para hacer la llamada.
  • Envuelva los valores devueltos de la misma manera para que pueda encadenar llamadas de una manera natural.
  • Mantenga una caché estática de ID de método por clase para evitar buscarlos cada vez.
  • Ser totalmente seguro para hilos, portable, de código abierto.
  • Compruebe automáticamente las excepciones después de cada método de llamada y producir una excepción std C++.
  • También funciona cuando estoy escribiendo métodos nativos en la forma habitual JNI, pero necesito llamar a otro código Java.
  • El array debe funcionar de manera totalmente consistente entre tipos primitivos y clases.
  • sin duda necesitará algo como global para envolver referencias cuando necesitan sobrevivir fuera de un marco de referencia local - de nuevo, debería funcionar igual para todas las referencias de matriz/objeto.

Hace tal libre, ¿existe una biblioteca/herramienta portátil de código abierto o estoy soñando?

Nota: Encontré esta pregunta existente pero la OP en ese caso no era tan exigente de perfección como lo estoy siendo yo...

Actualización: un comentario sobre SWIG me llevó a esta pregunta anterior, que parece indicar que se trata principalmente de la dirección opuesta y por lo tanto no haría lo que quiero.

IMPORTANTE

  • Se trata de poder escribir código C++ que manipula clases y objetos Java, no al revés (ver el título!)
  • Ya sé que el JNI existe (¡vea la pregunta!) Pero el código escrito a mano en las API de JNI es innecesariamente prolijo, repetitivo, propenso a errores, no se comprueba el tipo en tiempo de compilación, etc. Si desea almacenar en caché los ID de los métodos y los objetos de clase, es aún más detallado. Quiero generar automáticamente clases de envoltura de C++ que se encarguen de todo eso por mí.

Actualizar: He empezado a trabajar en mi propia solución:

Https://github.com/danielearwicker/cppjvm

Si esto ya existe, por favor hágamelo saber!

NB. Si está considerando usar esto en su propio proyecto, siéntase libre, pero tenga en cuenta que en este momento el código tiene unas pocas horas de antigüedad, y solo escribí tres pruebas muy poco frecuentes hasta ahora.

Author: Community, 2011-09-24

10 answers

Sí, existen herramientas que hacen exactamente esto generate generar envoltorios de C++ para clases Java. Esto hace que el uso de las API de Java en C++ sea más transparente y agradable, con menor costo y riesgo.

El que más he usado es JunC++ion. Es maduro, potente y estable. El autor principal es muy agradable, y muy sensible. Desafortunadamente, es un producto comercial, y caro.

Jace es una herramienta gratuita de código abierto con licencia BSD. Han pasado años desde La última vez que jugué con Jace. Parece que todavía hay algo de desarrollo activo. (Todavía recuerdo el post de USENET del autor original, hace más de una década, haciendo básicamente la misma pregunta que usted está haciendo.)

Si necesita admitir callbacks de Java a C++, es útil definir clases de C++ que implementen interfaces Java. Al menos JunC++ion le permite pasar tales clases de C++ a métodos Java que reciben devoluciones de llamada. La última vez que probé jace, no soportaba esto but pero eso fue siete hace años.

 16
Author: Andy Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-27 21:16:13

Soy uno de los arquitectos de prinicpal para los productos de integración de lenguaje de Codemesh, incluyendo JunC++ion. Llevamos haciendo este tipo de integración desde 1999 y funciona muy bien. El mayor problema no es la parte del JNI. JNI es tedioso y difícil de depurar, pero una vez que lo haces bien, en su mayoría solo sigue funcionando. De vez en cuando, se rompe por una JVM o una actualización del sistema operativo, y luego tienes que ajustar su producto, pero en general es estable.

El mayor problema es El escriba el mapeo del sistema y las compensaciones entre la usabilidad general y la solución específica. Por ejemplo, afirma que no le gusta el hecho de que JACE trate todas las referencias de objetos como globales. Hacemos lo mismo (con algunas escotillas de escape) porque resulta que este es el comportamiento que funciona mejor para el 95% de los clientes, incluso si perjudica el rendimiento. Si vas a publicar una API o un producto, tienes que elegir los valores predeterminados que hacen que las cosas funcionen para la mayoría de la gente. Selección de referencias locales como la opción predeterminada sería incorrecta porque cada vez más personas están escribiendo aplicaciones multiproceso, y muchas API de Java que la gente quiere usar de otros lenguajes son intrínsecamente multiproceso con devoluciones de llamada asíncronas y similares.

También descubrimos que realmente desea darle a la gente un generador de código basado en GUI para crear la especificación de integración. Una vez que lo hayan especificado, usa la versión de CLI para integrarlo en la compilación nocturna.

Buena suerte con tu proyecto. Es mucho trabajo hacerlo bien. Pasamos varios años en él y todavía lo estamos mejorando regularmente.

 7
Author: Alexander Krapf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-28 14:25:11

Tuve más o menos los mismos problemas, terminé haciéndolo por mi cuenta, tal vez esto ayude a alguien.

Https://github.com/mo22/jnipp

Tiene una pequeña huella de tiempo de ejecución ( stringArray; y luego usando stringArray[1]->getBytes() o algo así.

 4
Author: Moritz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-05 21:03:43

Llamando a Java desde C++.

Puede hacer lo que desee, pero debe dejar que Java tenga el control. Lo que quiero decir con esto es que se crean hilos de Java que llaman a código nativo y desde allí se bloquean, tipo de espera de su código nativo para darle algo que hacer. Crea tantos subprocesos Java como necesite para obtener suficiente trabajo / throuhput hecho.

Así que su aplicación C++ se inicia, crea un JVM / JavaVM (según la forma documentada, ejemplo existe en qtjambi codebase ver a continuación), esto a su vez realiza la inicialización y el sistema JNI habituales.LoadLibrary () y proporciona frascos con enlace "nativo". Luego inicializas un montón de subprocesos y llamas a algún código JNI (que creaste) donde pueden bloquear a la espera de que tu código C++ les dé algo de trabajo que hacer.

Su código C++ (presumiblemente de otro subproceso) luego se configura y pasa toda la información necesaria a uno de los trabajadores de subprocesos Java bloqueados y en espera, luego se le da la orden de ejecutarse, luego puede ir de vuelta en código Java puro para hacer el trabajo y volver con un resultado.

...

Es posible configurar, crear y contener una instancia JavaVM a partir de código C++. Esto puede ser forzado a alimentar su propio CLASSPATH/JARs para configurar el entorno contenido que necesita encapsulado dentro de su programa C++.

Esbozo de eso como estoy seguro que ya lo has encontrado en http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

...

Hay una especie de C++ = > Java JNI generator en el proyecto QtJambi (en el que trabajo y ayudo a mantenerlo). Esto es bastante personalizado para el kit de herramientas de Qt, pero esencialmente traduce un montón de archivos de encabezado de C++ en una colección de C++ .cpp / .archivos h y *.archivo java para proporcionar enlace y contención de shell del objeto para que los esquemas de asignación de memoria de la competencia jueguen bien juntos. Tal vez haya algo que sacar de esto.

Esto es ciertamente una prueba en cencept para lo que usted está pidiendo el generador simplemente pasa a estar contenido en el proyecto qtjambi (pero podría hacerse independiente con un poco de trabajo) y esto es LGPL licenciado (código abierto). El kit de herramientas de Qt no es una API pequeña, pero puede generar 100 clases para cubrir un alto % de la API (>85% y casi 100% de las partes del núcleo/GUI).

HTH

 2
Author: Darryl Miles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-26 19:21:00

El artículo Java Tip 17: Integración de Java con C++ describe cómo hacerlo en detalle.

 1
Author: Douglas Treadwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-24 20:37:00

También tuve muchas dificultades conseguir que JNI trabaje en diferentes sistemas operativos, lidiando con arquitecturas de 32/64 bits y asegurándose de que se encontraron y cargaron las bibliotecas compartidas correctas. Me pareció que CORBA (MICO y JacORB) también era difícil de usar.

No encontré una forma efectiva de llamar desde C / C++ a Java y mis soluciones preferidas en esta situación son para ejecutar mi código Java como:

  1. Un programa independiente que puedo ejecutar fácilmente desde programas C / C++ con java -cp myjar.jar org.foo.MyClass. Supongo esto es demasiado simplista para su situación.

  2. Como mini-servidor, aceptando solicitudes de C / C++ programas en un socket TCP/IP y devolviendo resultados a través de este zócalo también. Esto requiere escribir funciones de red y serialización pero desacopla los procesos C / C++ y Java y puede claramente identifique cualquier problema que esté en el lado C++ o en el lado Java.

  3. Como Servlet en Tomcat y hacer peticiones HTTP desde mi C / C++ programa (otros contenedores servlet también funcionarían demasiado). Esto también requiere escribir funciones de red y serialización. Esto es más como SOA.

 1
Author: Simon C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-26 23:40:07

¿Qué hay de usar Thrift o Protocol Buffers para facilitar sus llamadas de Java a C++?

 1
Author: MattRing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-27 16:43:04

Tal vez un martillo demasiado grande para este clavo, pero ¿no es para eso para lo que CORBA fue construido?

 0
Author: Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-26 21:01:39

Dado que CORBA no parece ser lo que quieres, aquí hay enlaces que describen cómo iniciar JVM desde C/C++ y llamar a JAVA-methods.

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

PD: Al interconectar Java con C++, también debe echar un vistazo a JNA o bridj.

 0
Author: Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-26 22:54:09

Respondiendo a mi propia pregunta:

Http://java4cpp.kapott.org/

No parece ser un proyecto activo. El autor recomienda que no se utilice con JDK 1.5 o posterior.

Parece tener un problema serio: pasa alrededor de punteros desnudos a sus objetos wrapper:

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

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

También causa un problema más sutil que para representar la compatibilidad de asignaciones (por ejemplo, una clase como un subtipo de la interfaz que implementa) los wrappers tienen que heredar de mutuamente.

 0
Author: Daniel Earwicker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-28 08:24:53